2

I'm using IDA to poke around in an old video game and noticed there are lots of calls to the printf function:

I can see in another function that dword_5CE914 is a bitmask comprising various startup arguments (e.g. debug, nofullscreen, etc). As you may have guessed, 0x4000000 is the value that indicates the debug switch was present; despite enabling this, there is no visible debug output.

As someone new to software programming, I assume that during the game's development the printf calls would have been outputting to a debugger/console window which were disabled for production.

My question is: how can I view the output now that there is no debugger window?

My current thought process would be to:

  1. Create a custom DLL containing a function to output arbitrary text to a .txt file
  2. Inject the DLL into the game's address space
  3. Hook into printf and pass the argument into my function which saves the output

Does that sound like a plausible approach, or can someone recommend a better way?

3
  • Set the dword @ 5ce914 to 0xffffffff
    – blabb
    Apr 2, 2021 at 4:10
  • @blabb I can easily change the dword and view the output with breakpoints, but I'm asking how to save the output to a log file or print to a console window. Apr 2, 2021 at 11:55
  • oh i see have you checked using an AttachConsole() to the pid of the process
    – blabb
    Apr 2, 2021 at 16:46

3 Answers 3

1

The approach you outlined seems plausible; I'd probably do something similar to that if I were approaching this problem. If printf is being called via function pointer -- say, it's an import from another .DLL -- you could simply overwrite its IAT entry with the one in your DLL. Otherwise, I'd go with hooking printf directly, and passing the arguments onto vfprintf in my DLL.

2
  • Thank you; I'll give this a try later and see how I get on. Apr 2, 2021 at 12:01
  • vfprintf works perfectly. Thanks again. Apr 4, 2021 at 14:26
1

If you convert the program to a console one (e.g. using EDITBIN), you should be able to run it from a console window and see everything it prints.

1

ok I was wondering how one could include printf() intact but run without console
it seems if one uses WinMain() and compile with /subsystem:windows one can achieve this
here is a sample code

#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);
}

compiling this with in vs 2017 community

cl /Zi /W4 /analyze /Od /nologo /EHsc foo.cpp /link /release /subsystem:windows  user32.lib  

this runs without console but keeps printf intact which prints to the console that is Created By AttachConsole() on the pid of binary

open foo.exe in x64dbg run to
WinMainCrtStartup or @$exentry aka PEHeader->AddressOFEntryPoint
so that all dll init are done
open file->attach and note the pid of foo.exe
in the stack use push qword
and push pid
push return address which is WinmainCRTStartup
use Ctrl+g to go to kernelbase.AllocConsole
step over the function and return to WinMainCRTStartup
pop the pid using pop qword in stack

set the global to 0xffffffff
f9 to run the exe
you will get all the printfs in the newly created console
see the attached screenshot
enter image description here

edit :

what igorsk suggested in his answer is a better option adding a test of the same

:\>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:

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.