熟悉PE结构的请进,如何取 .rdata 中的数据呢?

shier2817 2012-02-12 04:23:04
按照网上资料,我现在按照PE结构自己读取资源节已经没有什么问题了——因为网上资料上对资源部分的结构描述的还算详细,所以按照原理总是可以写出来的。

而.rdata 段,貌似有全部变量和常量吧,这个却没找到资料描述是以什么样子的格式(或者说结构)存储的,那到底该怎么读取呢?
========================================

之所要读取这个段,原因是这样的:
找到一个第三方的程序,里面有一段字符串我想要修改,但是他不在资源节里,也就是这个字符串是属于汉化领域所谓的“非标资源”。
当然,我向简单修改的话,只需要使用二进制编辑器(如UE)查找数据并修改保存就可以了。
但是第一这个程序更新频繁,第二我的目的是想利用学到的PE结构知识写个通用的“内存”补丁,在程序启动时在内存中修改,免得每次都要查找修改(在其资源节中也有需要修改的地方,我已经写完了,证实可用)!

我用PE结构的方式遍历过这个程序的各个节并取出各自的二进制数据,发现我想要修改的数据就是在.rdata 段中。
当然,我知道这个段的属性是只读的,但是我发帖子问的不是“如何修改只读”的问题,这个我想修改段的属性可以解决吧(即使解决不了也没关系,我的目的是加深对PE结构的了解)

所以我的问题就是怎么用PE结构的方式读取到.rdata的数据(不是读入二进制在查找数据的方法哦,因为我要写内存补丁)。
请前辈们帮帮忙,其实最关键的只要有前辈能给出这部分的数据的存储结构就可以了,感激不尽!!!
...全文
697 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
「已注销」 2012-02-17
  • 打赏
  • 举报
回复
这个问题还是没有解决。。。
Lactoferrin 2012-02-14
  • 打赏
  • 举报
回复
先仔细检查你的代码
不能过于肯定,毕竟刚才说的就是通用的方法
「已注销」 2012-02-14
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 lactoferrin 的回复:]
你找到rdata的pointertorawdata
和rawdatasize就可以巴rdata读到内存,然后搜索字符串,找到字符串的节内偏移,加上rdata的virtualaddr即可
[/Quote]

你说的这个不跟我上面的理解一样吗???(rawdatasize 应该是 SizeOfRawData 吧,只是这个大小你说的与我不一样)。我测试过了。。。结果一样都是错的,无论是在文件中搜索还是在内存中搜索(因为这与我上面说的方法找到的文件起始位置(即 pointertorawdata)都是一样的,所以结果必然还是不对喽)
Lactoferrin 2012-02-14
  • 打赏
  • 举报
回复
你找到rdata的pointertorawdata
和rawdatasize就可以巴rdata读到内存,然后搜索字符串,找到字符串的节内偏移,加上rdata的virtualaddr即可
Lactoferrin 2012-02-13
  • 打赏
  • 举报
回复
先说你的计算方法
「已注销」 2012-02-13
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 lactoferrin 的回复:]
你先找到rdata在文件中的位置
[/Quote]
不懂。。。按照我上面的说法,我遍历节表数组,数组每个成员的 PointerToRawData 不就是文件偏移吗?
只要这个成员指定的 PointerToRawData 开始、VirtualSize 大小的数据中包含了我需要的,那么:
1、它的 PointerToRawData 不就应该是你所说的rdata在文件中的位置吗???这个位置 + 在文件中找到要修改的数据偏移量,理论上在文件中就可以取到与“要修改的数据”同样的二进制数据吧?但实际却不是这样。。。
2、它的 VirtualAddress 不就应该是我要找的那个节的RVA吗???然后我只要这个 RVA + 在文件中找到我要修改的数据偏移量,理论上在程序运行时就可以取到与“要修改的数据”同样的二进制数据吧(当然要加基址ImageBase)?但实际却不是这样。。。

感觉像是对的,但实践证明我说的这些都不对。。。但是为什么呢???唉!
Lactoferrin 2012-02-13
  • 打赏
  • 举报
回复
你先找到rdata在文件中的位置
「已注销」 2012-02-13
  • 打赏
  • 举报
回复
晕了。。我发现我这种方法确实不对。。。我又测试了下,即使不去读内存,我只在文件中读 P1 位置的二进制数据,也不是我需要的那段二进制字符串数据啊。。。

到底该怎么计算呢???
「已注销」 2012-02-13
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 lactoferrin 的回复:]
先说你的计算方法
[/Quote]
因为我使用的是易语言,CSDN没这个版块,所以发在这里,因此我就不写易语言的代码了,我描述下我的方法:
1、对于资源节的获取:
DOS头偏移找到NT头,NT头+24字节找到可选头,可选头+可选头结构的大小就找到 节表数组开始的位置;
获取可选头最后一个数组成员中的第三个成员(资源目录)的 VirtualAddress(RAV1),然后遍历节表数组,判断 当前数组.VirtualAddress ≤ RAV1 ≤ 当前数组.VirtualAddress + 当前数组.VirtualSize 的话,那么 当前数组.PointerToRawData 就是资源节在文件中的偏移量,然后再分析资源数据就可以找到我想修改的部分了。。。
2、对于我修改的那个字符串的获取:
我不知道怎么用上面类似先获取第三个数据目录的 VirtualAddress 方法(资源节是固定的3,我却不知道我要找的字符串到底是几)。。。
所以我是这样找的:
同上,在找资源的时候,到了遍历节表数组时,我获取每个节表数组.PointerToRawData,然后通过这个文件偏移,我读取出 当前数组.VirtualSize 个大小的二进制数据 *B,然后我在 *B 中寻找我想要修改的那个字符串的二进制数据,发现确实能找到,并且此时判断 当前数组.Name 成员,名称确实是 .rdata。找到的位置 X 是相对于 *B 的,然后通过 X + 当前数组.PointerToRawData 就可以计算出我要修改的字符串相对于整个文件的偏移 P1,但这个是文件中的偏移,内存中的RVA P2就是:
P2 = P1 - 数组.PointerToRawData + 数组.VirtualAddress 也就是 = X + 数组.VirtualAddress 我认为就是找到了 我要修改的字符串在内存中的 RVA,但是在程序运行时我获取该进程的内存数据,却不是我要修改的字符串。。。不知道我这样对不对啊。。。
「已注销」 2012-02-12
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 lactoferrin 的回复:]
那两个地址对你没帮助

既然你能找到位置,就能换成rva
你现在能不能编程找到rdata的VirtualAddress和PointerToRawData
[/Quote]

当然可以了啊。。。但是找到rdata的VirtualAddress和PointerToRawData之后该怎么操作呢?我尝试过好几种方式想要计算出我要查找的那个字符串的RVA,但当该程序运行时,我读取他的进程内存,却不是我想要的数据啊(我读取的方法应该没有问题,因为我读取资源节的内存数据都是完全正确的)
Lactoferrin 2012-02-12
  • 打赏
  • 举报
回复
那两个地址对你没帮助

既然你能找到位置,就能换成rva
你现在能不能编程找到rdata的VirtualAddress和PointerToRawData
「已注销」 2012-02-12
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 lactoferrin 的回复:]
那就在rdata里面暴力搜索
[/Quote]
暴力搜索?是不是就是在该段搜索我需要的字符串的二进制位置呢?我这样尝试过,是可以找到一个位置的,但是我写的是内存补丁,找到位置后我也尝试将其换成RVA,可貌似是无效的,我调试该程序运行时读取这个RVA的内存数据,不是我要的字符串!

[Quote=引用 4 楼 baby393 的回复:]
楼主可以参考一下:
http://hi.baidu.com/gufengboy/home
http://hi.baidu.com/ses2010/blog/item/d0b5fa20da4ea4be4623e8a1.html

找资料最好还是到codeproject/codeguru去,鬼子还是比较专业的。
[/Quote]
这2个资料我确实没翻到哦,还是很详细的,值得学习。
但是这2篇文章关于.rdata的部分,都是说如何写入一个导入表结构信息,就是DLL引用的部分,没有提及到字符串常量的部分啊。。。这貌似跟我的需求不符啊。。。
baby393 2012-02-12
  • 打赏
  • 举报
回复
楼主可以参考一下:
http://hi.baidu.com/gufengboy/home
http://hi.baidu.com/ses2010/blog/item/d0b5fa20da4ea4be4623e8a1.html

找资料最好还是到codeproject/codeguru去,鬼子还是比较专业的。
Lactoferrin 2012-02-12
  • 打赏
  • 举报
回复
那就在rdata里面暴力搜索
「已注销」 2012-02-12
  • 打赏
  • 举报
回复
。。。那该怎么查呢?我这个程序之后4个段,分别是:
* “节表名称” | “.text”
* “节表名称” | “.rdata”
* “节表名称” | “.data”
* “节表名称” | “.rsrc”
没有 .reloc ,我该如何确定字符串的地址呢???
Lactoferrin 2012-02-12
  • 打赏
  • 举报
回复
没有规定的结构,里面放的常量,字符串,在代码中有地址就行,不需要什么组织结构
变量不会放在rdata,因为只读
如果那个模块有.reloc,你可以在那里面搜索字符串的地址
在编写程序的过程,我遇到了这样的需求:在基于Windows 9x 或 Windows NT4.0 的程序,要求确定键盘、鼠标处于空闲状态的时间。查询了有关资料文档以后,发现Windows 9x和Windows NT4.0 没有提供API或系统调用来实现这样的功能。但是,在Windows 2000提供了一个新的函数:GetLastInputInfo(),这个函数使用结构 LASTINPUTINFO 作为参数: LASTINPUTINFO lpi; lpi.cbSize = sizeof(lpi); GetLastInputInfo(&lpi); 调用函数GetLastInputInfo()以后, 结构成员lpi.dwTime 的值便是自上次输入事件发生以后的毫秒数。这个值也就是键盘、鼠标处于空闲状态的时间。可惜的是这个函数只能在Windows 2000使用,Windows 9x 或Windows NT4.0不提供此API函数。那么,如何在Windows 9x 或Windows NT4.0实现GetLastInputInfo()的功能呢?笔者的方法是利用系统钩子对键盘、鼠标行监控。 Windows的钩子实际上是一个回调函数,当用户有输入动作的时候,Windows要调用这个函数。比较典型的系统钩子应用就是键盘钩子和鼠标钩子: HHOOK g_hHookKbd = NULL; HHOOK g_hHookMouse = NULL; 在Windows,一个系统(相对于一个特定程而言)钩子必须用一个动态链接库(DLL)来实现。不妨将这个动态链接库命名为IdleUI.dll。 这个动态链接库在Windows 9x和Windows NT4.0 实现了GetLastInputInfo()的功能。IdleUI.dll有三个函数: BOOL IdleUIInit() void IdleUITerm(); DWORD IdleUIGetLastInputTime(); IdleUIInit()是环境初始化函数,IdleUITerm()是环境清理函数,分别在MFC应用程序的InitInstance() 和 ExitInstance()调用它们。当用IdleUIInit()做完初始化后,就可以调用第三个函数IdleUIGetLastInputTime()来获最后一次输入事件后的时钟。从而实现与GetLastInputInfo()一样的功能。程序TestIdleUI.exe是用来测试IdleUI动态库的,程序调用了IdleUIInit 和 IdleUITerm,同时在程序的客户区间显示键盘、鼠标空闲的秒数。 void CMainFrame::OnPaint() { CPaintDC dc(this); CString s; DWORD nsec = (GetTickCount() - IdleUIGetLastInputTime())/1000; s.Format( "鼠标或键盘空闲 %d 秒。",nsec); CRect rc; GetClientRect(&rc); dc.DrawText(s, &rc, DT_CENTER|DT_VCENTER|DT_SINGLELINE); } 图一显示了TestIdleUI运行时的情形。 图一 TestIdleUI运行画面 为了连续的显示,TestIdleUI设置刷新定时器间隔为一秒。 void CMainFrame::OnTimer(UINT) { Invalidate(); UpdateWindow(); } 运行TestIdleUI,当键盘和鼠标什么也不做时,可以看到计时器跳动,当移动鼠标或按键时,计时器又恢复到零,这样就实现了对输入设备空闲状态的监控。实现细节看下面对IdleUI.dll工作原理的描述: 首先调用IdleUIInit ()行初始化,安装两个钩子:一个用于监控鼠标输入,一个用于监控键盘输入。 HHOOK g_hHookKbd; HHOOK g_hHookMouse; g_hHookKbd = SetWindowsHookEx(WH_KEYBOARD,MyKbdHook,hInst, 0); g_hHookMouse = SetWindowsHookEx(WH_MOUSE,MyMouseHook,hInst, 0); 当用户移动鼠标或按下键盘键时,Windows调用其的一个钩子并且钩子函数开始记录时间: LRESULT CALLBACK MyMouseHook(in

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧