好的,我想知道如何完整地包含 printf() 但在没有控制台的情况下运行
似乎如果使用 WinMain() 并使用 /subsystem:windows 编译可以实现
这里是一个示例代码
#include <stdio.h>
#include <windows.h>
int pringlob = 0;
int a = 9;
int b = 10;
int c = 33;
int WINAPI WinMain(_In_ HINSTANCE,_In_opt_ HINSTANCE,_In_ LPSTR, _In_ int)
{
if ((pringlob & 0x400000) != 0)
{
printf("this is mytest\n");
if ((pringlob & 0x400000) != 0)
{
printf("this is mytest 1 %d\n", a);
if ((pringlob & 0x400000) != 0)
{
printf("this is mytest 2 %d\n", b);
if ((pringlob & 0x400000) != 0)
{
printf("this is mytest 3 %d\n", c);
}
}
}
}
MessageBoxA(NULL,"NO CONSOLE TEST","NO CONSOLE USE ATTACHCONSOLE",MB_OK);
}
在 vs 2017 社区中编译这个
cl /Zi /W4 /analyze /Od /nologo /EHsc foo.cpp /link /release /subsystem:windows user32.lib
这在没有控制台的情况下运行,但保持 printf 完好无损,它打印到由 AttachConsole() 在二进制文件的 pid 上创建的控制台
在 x64dbg 中打开 foo.exe 运行到
WinMainCrtStartup 或 @$exentry aka PEHeader->AddressOFEntryPoint
这样所有 dll init 都完成了
open file->attach 并注意
堆栈中 foo.exe 的 pid使用 push qword
和 push pid
push return address这是 WinmainCRTStartup
使用 Ctrl+g 转到 kernelbase.AllocConsole
跳过该函数并返回到 WinMainCRTStartup
使用 pop qword in stack 弹出 pid
将全局设置为 0xffffffff
f9 以运行 exe
您将在新创建的控制台中获得所有 printfs,
请参阅附加的屏幕截图

编辑 :
igorsk 在他的回答中建议的是添加相同测试的更好选择
:\>ls -lg
total 2
-rw-r--r-- 1 197121 91 Apr 3 02:01 complink.bat
-rw-r--r-- 1 197121 595 Apr 2 23:45 fook.cpp
:\>complink.bat
:\>cl /Zi /W4 /Od /EHsc /nologo /analyze fook.cpp /link /release /subsystem:windows user32.lib
fook.cpp
:\>dumpbin /headers fook.exe | grep -i subsystem
6.00 subsystem version
2 subsystem (Windows GUI)
:\>editbin /subsystem:console fook.exe
Microsoft (R) COFF/PE Editor Version 14.16.27045.0
Copyright (C) Microsoft Corporation. All rights reserved.
:\>dumpbin /headers fook.exe | grep -i subsystem
6.00 subsystem version
3 subsystem (Windows CUI)
:\>cdb -c "ed fook!pringlob 0xffffffff;g;q" fook.exe | awk "/Reading/,/quit/"
0:000> cdb: Reading initial command 'ed fook!pringlob 0xffffffff;g;q'
xxxxxxxxxx
this is mytest
this is mytest 1 9
this is mytest 2 10
this is mytest 3 33
quit: