考虑以下代码:
#include <stdio.h>
#include <inttypes.h>
#include <Windows.h>
int f(int x)
{
return x+1;
}
// using vs 2019 debug|x86
int main()
{
// visual studio's creates a label for f, which eventually jumps to it's implmentation.
// the jump instruction is E9, then an offset to the implementation.
// this calculates the actual address of f, by getting f+5(the length of the jump instruction)+the jump offset
unsigned char *fAddr = (unsigned char*)f + 5 + *(int*)((char*)f + 1);
printf("printing f bytes (pid %d at 0x%" PRIXPTR "):\n", GetCurrentProcessId(), fAddr);
int fLen = 0x45; // for me, function size was 0x42
for (int i = 0; i < fLen;)
{
for (int j = 0; j < 10 && i < fLen; ++j)
printf("%02X ", fAddr[i++]);
printf("\n");
}
getchar();
return 0;
}
上面的代码基本上会打印f
的代码字节。
现在,如果我在f
中放置一个软件断点,则该字节值将变为0xCC。
这将在main
打印f
时反映出来。
我希望在断点的地址上调用ReadProcessMemory时,我也会得到0xCC而不是原始字节值。 当我使用Visual Studio设置断点时,确实发生了这种情况。 但是,当我使用WinDbg设置断点时,ReadProcessMemory返回原始字节值。
编辑: 这是我用来调用ReadProcessMemory的代码:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <inttypes.h>
#include <Windows.h>
int main()
{
int *fPid;
int *fAddr;
printf("Please enter the pid of f (upper case hex digits, no 0x): ");
scanf("%X", &fPid);
printf("Please enter the address of f (upper case hex digits, no 0x): ");
scanf("%X", &fAddr);
printf("printing f bytes (pid 0x%X at 0x%X):\n", fPid, fAddr);
HANDLE process;
if ((process = OpenProcess(PROCESS_VM_READ, FALSE, fPid)) == INVALID_HANDLE_VALUE)
{
DWORD err = GetLastError();
printf("OpenProcess error: %d\n", err);
char cmd[100];
sprintf(cmd, "net helpmsg %d", err);
system(cmd);
return 1;
}
int fLen = 0x45;
unsigned char *buf = malloc(fLen);
if (!ReadProcessMemory(process, fAddr, buf, fLen, NULL))
{
DWORD err = GetLastError();
printf("ReadProcessMemory error: %d\n", err);
char cmd[100];
sprintf(cmd, "net helpmsg %d", err);
system(cmd);
return 1;
}
for (int i = 0; i < fLen;)
{
for (int j = 0; j < 10 && i < fLen; ++j)
printf("%02x ", buf[i++]);
printf("\n");
}
free(buf);
return 0;
}
关于断点,在VS中,我只是在return x+1
上设置了一个断点。
在WinDBG中,假设模块(exe)名称为bp cpp_exe!f+20
,则使用cpp_exe
。
答案 0 :(得分:1)
所以我想我已经解决了。
使用WinDBG调试并且运行debgugee时,ReadProcessMemory返回正确的值(这意味着我可以看到0xCC字节)。 但是,当调试对象处于中断模式时,ReadProcessMemory会返回原始字节值。
另一方面,VS总是返回正确的值(0xCC字节,无论是运行还是处于中断模式)。
因此,我想每当WinDBG中断时,它实际上就会删除所有软件断点,并在您继续应用程序后立即将其恢复。 我猜这是一种有趣的方法,但至少有道理。