我正在尝试从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 ; ---------------------------------------------------------------------------
但是我仍然不确定这一点。
答案 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)