强制转换内存位置以获取字符串

Casting memory location to get String

本文关键字:获取 字符串 位置 内存 转换      更新时间:2023-10-16

我正在尝试从 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 ; ---------------------------------------------------------------------------

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

您通过间接寻址以错误的方式访问进程内存。 .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。此外,这是用于初始化成员变量的字符串常量,而不是变量本身。

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

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

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

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