1

I'm debugging an out-of-process COM server (an EXE), started by a dummy application I wrote. I attach the debugger when the instance is created and let the dummy application make calls to the server.

In the debugged process, I can see that it does lots of logging by calling sprintf. I would like to capture this output. Is there a way to do this with OllyDbg 2.01?

3

sprintf is a crt function superseded by sprintf_s both take a destination a format string and varargs no of arguments can range from one to several depending on the format string.

code for both these functions are normally embedded inside the binary (static) and needs to be located and a preparatory step needs to be done prior to logging the output that will get sprintf'fed to the Destination Buffer;

Ollydbg 1.10

output below shows both the start of both sprintf versions (note src is available for vc compiled exes cycle the comment column to make src visible)

sprintf 
00401147 >/$  8BFF          MOV     EDI, EDI         ; { sprintf.c:99. 

00401120 >/$  55            PUSH    EBP                              
; __DEFINE_CPP_OVERLOAD_SECURE_FUNC_0_1_ARGLIST(int, sprintf_s, vsprintf_s,
 _Deref_post_z_ char, _Dest, _In_z_ _Printf_format_string_ const char *, 
_Format) stdio.h:323. 

select the start of function right click analysis -> assume arguments -> select Sformat(ptr,format,.....) apply

output post assume argument operation cycle back to comment from src

00401147 >/$  8BFF          MOV     EDI, EDI     ;  Decoded as <Sformat>

00401120 >/$  55            PUSH    EBP          ;  Decoded as <Sformat>

now all you need is a non breaking conditional breakpoint to log all the sprintf output

select the start of function and click shift+f4 

set radio buttons as follows for both version

pause radio button                     never 
log expression radio button            never 
log function arguments radio button    always 

now simply f9 and you will have all the sprintf arguments logged to log window or a file you specify (right click in log window to set up file logging )

Breakpoints
Address                            Module              Active 
00401120 sprintlo.sprintf_s<128>   sprintlo            Log "logging sprintf_s_arguments"
00401147 sprintlo.sprintf          sprintlo            Log "logging sprint arguments" 

here is a sample output

Log data
CALL to Assumed Sformat from sprintlo.0040104F
  ptr = 0013FEE0
  format = "%s    %03d %s %p"
  <%s> = "sprint logging number"
  <%03d> = 0
  <%s> = "logme"
  <%p> = sprintlo.00401105
CALL to Assumed Sformat from sprintlo.004010BF
  ptr = 0013FEE0
  format = "%s    %03d %s %p"
  <%s> = "sprint logging number"
  <%03d> = 0
  <%s> = "logme"
  <%p> = sprintlo.00401111
  ==================================================================================
CALL to Assumed Sformat from sprintlo.0040104F
  ptr = 0013FEE0
  format = "%s    %03d %s %p"
  <%s> = "sprint logging number"
  <%03d> = 4
  <%s> = "logme"
  <%p> = sprintlo.00401105
CALL to Assumed Sformat from sprintlo.004010BF
  ptr = 0013FEE0
  format = "%s    %03d %s %p"
  <%s> = "sprint logging number"
  <%03d> = 4
  <%s> = "logme"
  <%p> = sprintlo.00401111
Process terminated, exit code 0

code used for demonstration

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <intrin.h>
void insecuresprintf(int in) {
    char dummybuff[0x80];
    memset(dummybuff,0,sizeof(dummybuff));
    void* pvAddressOfReturnAddress = _AddressOfReturnAddress();    
    sprintf(
        dummybuff,
        "%s    %03d %s %p\0\0","sprint logging number" ,
        in,"logme",*((void**) pvAddressOfReturnAddress)
        );
    return;
}
void securesprintf(int in) {
    char dummybuff[0x80];
    memset(dummybuff,0,sizeof(dummybuff));
    void* pvAddressOfReturnAddress = _AddressOfReturnAddress();    
    sprintf_s(
        dummybuff,
        "%s    %03d %s %p\0\0","sprint logging number" ,
        in,"logme",*((void**) pvAddressOfReturnAddress)
        );
    return ;
}
int main (void) { 
    for (int i =0; i<5; i++)    {
        insecuresprintf(i);
        securesprintf(i);
    }
    return 0;
}

ollydbg 2.01

instead of analysis assume arguments you have to shift + f4 directly and specify the function type there use format 2A (arg1,format,.....) but there is a bug in the function because of which the resulting strings are truncated out

INT3 breakpoints
Address   Module    Status       Disassembly                              Comment
00401120 >sprintlog Cond         PUSH    EBP                              INT sprintlog.sprintf_s<128>(_Dest,_Format)
00401147 >sprintlog Cond         MOV     EDI, EDI                         INT sprintlog.sprintf(string,format)

output from ollydbg 2.01 (notice %03d showing correct values but %p %s output are not visible )

Log data
00401147  Call to sprintlog.sprintf from sprintlog.0040104F
        0013FEE0  Arg1 = 13FEE0
        004131AC  Format = "%s    %03d %s %p"
        00413194  <%s> =
        00000000  <%03d> =
        0041318C  <%s> =
        00401105  <%p> =
00401120  Call to sprintlog.sprintf_s<128> from sprintlog.004010BF
        0013FEE0  Arg1 = 13FEE0
        004131E0  Format = "%s    %03d %s %p"
        004131C8  <%s> =
        00000000  <%03d> =
        004131C0  <%s> =
        00401111  <%p> =
========================================================================================
00401147  Call to sprintlog.sprintf from sprintlog.0040104F
        0013FEE0  Arg1 = 13FEE0
        004131AC  Format = "%s    %03d %s %p"
        00413194  <%s> =
        00000004  <%03d> =
        0041318C  <%s> =
        00401105  <%p> =
00401120  Call to sprintlog.sprintf_s<128> from sprintlog.004010BF
        0013FEE0  Arg1 = 13FEE0
        004131E0  Format = "%s    %03d %s %p"
        004131C8  <%s> =
        00000004  <%03d> =
        004131C0  <%s> =
        00401111  <%p> =
      Process terminated, exit code 0

btw it is incredibly simple with windbg

0:000> x *!sprintf*
7c925bc4 ntdll!sprintf = <no type information>
00401147 sprintlog!sprintf (void)
004011e7 sprintlog!sprintf_s (void)
00401120 sprintlog!sprintf_s<128> (char (*)[128], char *)
0:000> bp 00401120 "r $t1 = poi(@esp+4) ; gu; .printf \"%ma\\n\", @$t1 ; gc"
0:000> bp 00401147 "r $t1 = poi(@esp+4) ; gu; .printf \"%ma\\n\", @$t1 ; gc"
0:000> .bpcmds
bp0 0x00401120  "r $t1 = poi(@esp+4) ; gu; .printf \"%ma\\n\", @$t1 ; gc";
bp1 0x00401147  "r $t1 = poi(@esp+4) ; gu; .printf \"%ma\\n\", @$t1 ; gc";
0:000> g
ModLoad: 5cb70000 5cb96000   C:\WINDOWS\system32\ShimEng.dll
sprint logging number    000 logme 00401105
sprint logging number    000 logme 00401111
sprint logging number    001 logme 00401105
sprint logging number    001 logme 00401111
sprint logging number    002 logme 00401105
sprint logging number    002 logme 00401111
sprint logging number    003 logme 00401105
sprint logging number    003 logme 00401111
sprint logging number    004 logme 00401105
sprint logging number    004 logme 00401111
| improve this answer | |
1

I can think of these options:

1) Edit the .exe flags to mark it as a console process. E.g.

EDITBIN /SUBSYSTEM:CONSOLE comserver.exe

2) Use the debugger to call to AllocConsole() at runtime.

3) Put a breakpoint on the logging function and log the string contents in the breakpoint's action (not sure if it's doable in OllyDbg).

| improve this answer | |
0

sprintf doesnt "log" to standard output. it prints to a variable.

anyways: you could use a OllyDbgScript which sets a BP on sprintf and then use BPGOTOcommand to do some actions like dump the formatted variable and run again.

| improve this answer | |

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.