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