首页
社区
课程
招聘
[原创]PE解析逆向LoadString
发表于: 2015-8-27 21:27 12815

[原创]PE解析逆向LoadString

2015-8-27 21:27
12815

通过对LoadString的深入理解,也可加强对PE中资源表的理解

熟悉windows编程的朋友相信对资源都不陌生,在使用PE资源的时候,字符串资源也是大家经常使用的一种。下面就开始了解它的来龙去脉.

我们知道,LoadString的函数原型如下:
int LoadString(  HINSTANCE hInstance,  // handle to resource module
  UINT uID,             // resource identifier
  LPTSTR lpBuffer,      // resource buffer
  int nBufferMax        // size of buffer);

最后两个参数自不必说,第一个参数相信熟悉PE的朋友都能猜到它的意义,作为一个输入参数,它是必须的,我们需要模块基址从而定位到资源表。那么,问题来了,假如一个PE文件有多个字符串资源,那么怎么准确定位呢? 一个uID可以吗?
以我手上一个DEMO程序为例,


定义的资源如下:


两个字符串,ID 分别是101 和1000 
那么,在我们逆向之前,不妨先手工在PE文件找到对应的资源,顺便复习下PE中的资源表

首先,通过查询数据目录项中的第二项(从0开始) , 我们获取到资源表的RVA(相对基址偏移), 转成FOA(相对文件偏移)后,可以在文件中定位到它
以我的程序为例,

RVA  = 0x1A000
转成FOA后, 在文件偏移7000h处

我们知道,资源表主要由三层目录以及相应的详细数据构成,下图有详细说明:


目录项如下:
typedef struct _IMAGE_RESOURCE_DIRECTORY {
    DWORD   Characteristics;
    DWORD   TimeDateStamp;
    WORD    MajorVersion;
    WORD    MinorVersion;
    WORD    NumberOfNamedEntries;
    WORD    NumberOfIdEntries;
//  IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
以及紧随其后的
typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
    union {
        struct {
            DWORD NameOffset:31;
            DWORD NameIsString:1;
        } DUMMYSTRUCTNAME;
        DWORD   Name;
        WORD    Id;
    } DUMMYUNIONNAME;
    union {
        DWORD   OffsetToData;  //这里的OFFSET是相对资源节的偏移
        struct {
            DWORD   OffsetToDirectory:31;
            DWORD   DataIsDirectory:1;
        } DUMMYSTRUCTNAME2;
    } DUMMYUNIONNAME2;
} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;

先看第一层,
ID             OffsetToData
6            80000020
18            80000040
字符串类型的 ID编号为6 , 取offset的低位,定位到节偏移0x20处,我们来到第二层



上图第一行末尾的02说明本层有两个字符串,
ID            OffsetToData
07            80 00 00 58
3f            80 00 00 70
两个字符串编号别分为07 和 3F , 这个信息很重要,下面逆向要用到

最终通过第三层目录定位到实际的字符串在文件偏移的地址后,可以看到如下:


也就是说,我们手工定位,只能获取所有的 字符串,但是具体哪一个,还需要研究LoadString的第二个参数意义

下面开始进入逆向

我们只关心StringID这个参数,其余不做参考

向下走


又会调用LoadStringBaseExW这个函数 , 继续跟


又将参数压栈后调用RtlLoadString这个函数,继续跟入


在RtlLoadString里, 代码将字符串ID 右移 4位后 加一,写入到一个局部变量中,这个局部变量是我们需要关注的重点
继续向下:



刚才写入的位置是ebp-38 , 而ebp – 3c 是字符串资源的类型ID ,也就是 6
Ebp – 3c 和 ebp -38 在内存上连续,当做结构体传入第二个参数,进入内部call

在这个内部call里,代码首先调用RtlImageDirectoryEntryToData获得资源表的VA

然后进入三次循环,因为资源表的目录就是三层 ,所以我们还是只关注在第二层时,代码如何将上次stringID运算的结果与之匹配



代码到此,此时ESI = 0x 0018FC98 , 也就是指向stringID 右移运算的结果,作为第四个参数传入,我们跟进去这个call



进入之后,又将结果作为参数,传入到下一个call ,还是一样,继续跟



到此,思路就很清晰了,函数枚举每个IMAGE_RESOURCE_DIRECTORY_ENTRY项,然后取每一项的ID值和传入的ID值做比较,相等就是找到了目标
到了这里,离成功已经比较接近了,我们还是回到上层RtlLoadString中


此时edi 保存字符串块的首地址(0041A238),在pe中可以定位到如下:


在0x7238处,似乎离目标”ByeBye”还有一段距离

在RtlLoadString中继续向下找


这个时候看到,stringID 的 低四位发挥了作用 ,将算法简单还原一下如下
//edi 指向字符串块(第三层遍历之后的结果)
do 
{
  edx = cx
  edx = *(word*)(edi + edx * 2)
  ecx += edx + 1
  esi -= 1
} while (esi >=0);

char *szFinalString = (char*)edi + (ecx - edx) * sizeof(word)
此时szFinalString 指向”ByeBye”, 也就是我们定义的目标字符串

总结:
LoadString 先通过第二个参数uID ,将之右移加一后,和资源表第二层的每一项ID做对比,成功后可以通过第三层直接定位到目标字符串块
再通过uID的低四位获取到偏移, 加上字符串块的首地址,从而精确定位

写的匆忙,一些细节还没体现,不足和谬误之处请大家多多包涵



[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

上传的附件:
收藏
免费 4
支持
分享
最新回复 (11)
雪    币: 39
活跃值: (26)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
谢谢楼主,讲的很明白
2015-8-27 23:03
0
雪    币: 271
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
顶一个               .
2015-8-28 15:50
0
雪    币: 37
活跃值: (28)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
写的很详细噢, 绑顶
2015-8-28 17:15
0
雪    币: 256
活跃值: (48)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
讲的很仔细,谢谢分享
2015-8-28 22:12
0
雪    币: 12502
活跃值: (3053)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
6
感谢分享
2015-8-28 23:15
0
雪    币: 115
活跃值: (23)
能力值: (RANK:20 )
在线值:
发帖
回帖
粉丝
7
回帖是一种美德,不是吗!
2015-8-29 18:57
0
雪    币: 27
活跃值: (622)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
讲的很透彻-。-  thx
2015-8-29 21:39
0
雪    币: 8
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
很历害很历害
2015-8-31 13:12
0
雪    币: 2375
活跃值: (433)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
科锐是个培训机构?
2015-9-3 05:34
0
雪    币: 56
活跃值: (34)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
11
顶,多谢分享
2015-9-4 19:24
0
雪    币: 42
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
多谢分享 ..
2015-9-10 03:17
0
游客
登录 | 注册 方可回帖
返回
//