我正在调试由我编写的虚拟应用程序启动的进程外 COM 服务器(一个 EXE)。我在创建实例时附加调试器,并让虚拟应用程序调用服务器。
在调试过程中,我可以看到它通过调用 sprintf 进行了大量日志记录。我想捕获这个输出。有没有办法用 OllyDbg 2.01 做到这一点?
我正在调试由我编写的虚拟应用程序启动的进程外 COM 服务器(一个 EXE)。我在创建实例时附加调试器,并让虚拟应用程序调用服务器。
在调试过程中,我可以看到它通过调用 sprintf 进行了大量日志记录。我想捕获这个输出。有没有办法用 OllyDbg 2.01 做到这一点?
sprintf
是通过取代一个CRT函数sprintf_s
既采取destination
一个format string
和varargs
没有的参数可以从范围one to several
取决于格式字符串。
这两个函数的代码通常都嵌入在二进制文件(静态)中,需要定位,并且需要在记录将被 sprintf'馈送到目标缓冲区的输出之前完成准备步骤;
Ollydbg 1.10
下面的输出显示了两个 sprintf 版本的开始(注意 src 可用于 vc 编译的 exe 循环注释列以使 src 可见)
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.
选择函数的开始点右键分析 -> 假设参数 -> 选择 Sformat(ptr,format,.....) apply
输出 post 假设参数操作循环回到来自 src 的评论
00401147 >/$ 8BFF MOV EDI, EDI ; Decoded as <Sformat>
00401120 >/$ 55 PUSH EBP ; Decoded as <Sformat>
现在您只需要一个不间断的条件断点来记录所有 sprintf 输出
select the start of function and click shift+f4
为两个版本设置单选按钮如下
pause radio button never
log expression radio button never
log function arguments radio button always
现在只需按 f9,您就会将所有 sprintf 参数记录到日志窗口或您指定的文件(在日志窗口中右键单击以设置文件日志记录)
Breakpoints
Address Module Active
00401120 sprintlo.sprintf_s<128> sprintlo Log "logging sprintf_s_arguments"
00401147 sprintlo.sprintf sprintlo Log "logging sprint arguments"
这是一个示例输出
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
用于演示的代码
#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
而不是分析假设参数你必须直接 shift + f4 并指定函数类型那里使用格式 2A (arg1,format,.....) 但函数中有一个错误,因为它导致结果字符串被截断
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)
ollydbg 2.01 的输出(注意 %03d 显示了正确的值,但 %p %s 输出不可见)
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
顺便说一句,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
我可以想到这些选项:
1) 编辑 .exe 标志以将其标记为控制台进程。例如
EDITBIN /SUBSYSTEM:CONSOLE comserver.exe
2) 使用调试器AllocConsole()
在运行时调用。
3) 在日志函数上放置一个断点,并在断点的操作中记录字符串内容(不确定在 OllyDbg 中是否可行)。
sprintf 不会“记录”到标准输出。它打印到一个变量。
无论如何:您可以使用 OllyDbgScript 在 sprintf 上设置 BP,然后使用BPGOTO
command 执行一些操作,例如转储格式化的变量并再次运行。