1

我正在尝试从具有基于源代码的已知变量的 Win32 应用程序访问变量:

Foo foo; // Class foo
foo.mystring = "All your base are belong to us"; // where this is defined as: 'string mystring'

现在我尝试使用反汇编程序来反汇编 PE,我发现了这个

.rdata:00446074 aAllYourBaseAre db 'all your base are belong to us',0

现在我有另一个 win32 进程,它获取前一个 win32 应用程序的图像基地址,该应用程序具有我需要的类变量。

我使用以下代码获取进程地址:

HMODULE parent = ::GetModuleHandle(NULL);
if (parent) {
   const BYTE* imageBase = reinterpret_cast<const BYTE*> ( parent );
   const char* strMemberValue = *reinterpret_cast<const char**>((unsigned char*)imageBase + 0x00446074); 
            std::cout << "Value=" << strMemberValue;
}

父进程是我试图访问的进程。我还测试了父母是正确的过程。问题是,当我尝试通过转换基地址 + 偏移量来获取字符串时,我什么也得不到。

编辑:

我错过了我的观点。我无法重新编译目标 Win32 应用程序,它已经在生产中。但是我需要访问该可执行文件上的一些变量。我在这里的代码只是一个概念证明**

我也在做“DLL注入”

调试:

由于类是带有方法的结构,因此我假设我使用 IDAPro 挖掘的这段代码是Foo

00000000 ; ---------------------------------------------------------------------------
00000000
00000000 ; (Class Informer)
00000000 type_info       struc ; (sizeof=0x8, variable size)
00000000 vftable         dd ?                    ; offset (00000000)
00000004 _m_data         dd ?
00000008 _m_d_name       db 0 dup(?)             ; string(C)
00000008 type_info       ends
00000008
00000000 ; ---------------------------------------------------------------------------

但是,我仍然不确定这一点。

4

2 回答 2

1

您通过双重间接以错误的方式访问进程内存。.rdata:00446074是字符串所在的地址,而不是指向实际位置的指针。您应该像这样访问它:

HMODULE parent = ::GetModuleHandle(NULL);
if (parent) {
   const BYTE* imageBase = reinterpret_cast<const BYTE*> ( parent );
   const char* strMemberValue = (const char *)imageBase + 0x00446074; 
   std::cout << "Value=" << strMemberValue;
}

此外,您确定反汇编程序将映像基于0x0而不是基于默认 PE 基地址0x00400000,在这种情况下,字符串的 RVA 将是0x00046074而不是0x00446074。这也是用于初始化成员变量的字符串常量,而不是变量本身。

于 2012-06-22T09:20:27.280 回答
0

好的,首先要注意:在处理外部进程内存时,如果重新编译其他可执行文件,您可能不会再找到任何数据。链接器可以自由地将数据和代码放置在任何地方并重新排列。要重新查找某些值或函数,您必须搜索二进制模式。

接下来要注意的是:您实际上有一个成员变量。这意味着每个对象的内容实际上可能不同。您当前正在搜索默认分配给它的字符串(而不是直接分配给成员,而是在 std::string 类中的某个位置)。

最后但并非最不重要的一点是:当您尝试访问外部进程的内容时,您必须使用ReadProcessMemory。不过考虑使用共享内存进行进程间通信。命名管道也可以。

访问实际值的最简单方法是将Foo对象的地址传递&foo给您的读取过程,并将Foo类放在两个项目均可访问的公共项目库中。然后将整个对象读入您的地址空间(见ReadProcessMemory上文)并像访问任何其他成员一样访问该成员。请注意,您实际上是在处理真实对象的副本。共享内存可以使两个进程都可以访问单个对象(CreateFileMapping

于 2012-06-22T06:48:01.997 回答