转换内存位置以获取String

时间:2012-06-22 06:30:44

标签: c++ winapi

我正在尝试从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注入”

DEBUG:

由于类是带方法的结构,我假设使用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 ; ---------------------------------------------------------------------------

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

2 个答案:

答案 0 :(得分:1)

您正通过 double 间接以错误的方式访问进程内存。 .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,而不是基于0x00400000的默认PE基址,在这种情况下,字符串的RVA将为0x00046074而不是0x00446074。这也是用于初始化成员变量的字符串常量,而不是变量本身。

答案 1 :(得分:0)

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

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

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

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