首页
社区
课程
招聘
[求助]3.4节求助
2012-3-9 04:50 7842

[求助]3.4节求助

2012-3-9 04:50
7842
我在运行3.4节中的程序时,发现kernel32.dll中不存在LoadLibraryA函数,我是在原程序中加了条printf调用遍历输出的。这样的话程序无法运行,能解释下原因吗?

另外,原书3.4程序在next_function_loop处,此处inc edi会导致跳过第一个函数。虽然实际可能不影响。

附图是我检索出的函数名。

[CTF入门培训]顶尖高校博士及硕士团队亲授《30小时教你玩转CTF》,视频+靶场+题目!助力进入CTF世界

收藏
点赞0
打赏
分享
最新回复 (12)
雪    币: 83
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kenikehan 2012-3-9 10:52
2
0
1)kernel32.dll中存在LoadLibraryA函数啊,你没看仔细吧,发的图看不了,也无法深究了
2)第一次inc edi的确跳过了第一个函数,不过第一个函数显然不是我们定位的目标。如此做有一个节约字节的考量,源代码是
nexcfuction:inc edi
mov esi,[ebx+edi*4]
..........
mov di,[ebx+2*edi]
如果一个是不想跳过一个函数,可能的实现方式如下
nexcfuction:
mov esi,[ebx+edi*4]
inc edi

..........
dec edi
mov di,[ebx+2*edi]
这样,少用了一条dec指令哦,纯粹个人想法,仅供参考
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ccqmpux 2012-3-9 13:32
3
0
谢谢!

抱歉,图可能贴挂了。重新贴下

但在我的程序跑时,确实没有LoadLibraryA函数,只有LoadLibraryExA和LoadLibraryExW。这到底是为什么?

增加的输出代码可以从图中读出。param是全局char[]变量,值为"%s\n"。

你的第二个说的很对。
上传的附件:
雪    币: 83
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kenikehan 2012-3-9 15:28
4
0
哎,想了好久这个着实想不到为啥了,猜想两种可能
1)打印出来的函数名表中函数的排列顺序可能不像函数导出序号表中对函数排列的那么规律,你再一个一个找找看吧
2)你的系统版本太新,微软新的安全机制下,干脆删除了kenel32.dll中的这个函数改用LoadLibraryExA了?估计不太可能啊。

要不你用pe工具去系统目录下差一下kenel32.dll看看,确定是不是正的没有LoadLibraryA这个函数了
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ccqmpux 2012-3-10 15:55
5
0
我用pe工具打开kernel32.dll,里面确实是有LoadLibraryA函数,但直接遍历确实找不到。
上传的附件:
雪    币: 83
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kenikehan 2012-3-10 20:07
6
0
我怀疑被你引入误区了,可能你没有遍历吧,我一直是在假设你完全遍历的前提下思考,哎,你的遍历是在原有shellcode上增加几条指令实现的一个函数名打印输出吧,这样就会存在纰漏(shellcode可没有遍历啊,而是找到就收),你必须确保未修改原shellcode前能顺利执行exp,在这种情况下再加入打印输出函数名的功能,如果shellcode执行失败,那么可能在搜索到loadlibrarya函数之前就发生了hash碰撞,程序流程就跳转了,由于不是遍历,流程不会继续搜索余下的函数名并且打印输出还未搜索到的loadlibrarya函数,还有为了保险起见,修改一下指令避免第一个函数的遗漏。或者你完全自己写一个遍历dll导出函数的程序看看
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ccqmpux 2012-3-11 01:42
7
0
我肯定遍历了,我贴下代码吧,就是基于原书章节改的,我都把hash去掉了。
#include <stdio.h>
char param[] = "%s\n";
int main()
{       
        _asm{
                        CLD                                        ; clear flag DF
                        ;store hash
                        push 0x1e380a6a                ;hash of MessageBoxA
                        push 0x4fd18963                ;hash of ExitProcess
                        push 0x0c917432                ;hash of LoadLibraryA
                        mov esi,esp                        ; esi = addr of first function hash
                        lea edi,[esi-0xc]        ; edi = addr to start writing function
                        ; make some stack space
                        xor ebx,ebx
                        mov bh, 0x04                          
                        sub esp, ebx
                        ; push a pointer to "user32" onto stack
                        mov bx, 0x3233                 ; rest of ebx is null
                        push ebx
                        push 0x72657375
                        push esp
                        xor edx,edx
                ; find base addr of kernel32.dll
                        mov ebx, fs:[edx + 0x30]         ; ebx = address of PEB
                        mov ecx, [ebx + 0x0c]                 ; ecx = pointer to loader data
                        mov ecx, [ecx + 0x1c]                 ; ecx = first entry in initialisation order list
                        mov ecx, [ecx]                                 ; ecx = second entry in list (kernel32.dll)
                        mov ebp, [ecx + 0x08]                 ; ebp = base address of kernel32.dll
            mov eax, [ebp + 0x3C]
            mov edx, [ebp + eax + 0x78]
            add edx, ebp
            mov ecx, [edx + 0x18]
            mov ebx, [edx + 0x20]
            add ebx, ebp
search:
            dec ecx
            mov esi, [ebx + ecx * 4]
            add esi, ebp
                find_lib_functions:
                        lodsd                                         ; load next hash into al and increment esi
                        cmp eax, 0x1e380a6a                ; hash of MessageBoxA - trigger
                                                                        ; LoadLibrary("user32")
                        jne find_functions
                        xchg eax, ebp                         ; save current hash
                        call [edi - 0x8]                 ; LoadLibraryA
                        xchg eax, ebp                         ; restore current hash, and update ebp
                                                                        ; with base address of user32.dll
                       
                       
                find_functions:
                        pushad                                                 ; preserve registers
                        mov eax, [ebp + 0x3c]                ; eax = start of PE header
                        mov ecx, [ebp + eax + 0x78]        ; ecx = relative offset of export table
                        add ecx, ebp                                 ; ecx = absolute addr of export table
                        mov ebx, [ecx + 0x20]                 ; ebx = relative offset of names table
                        add ebx, ebp                                 ; ebx = absolute addr of names table
                        xor edi, edi                                 ; edi will count through the functions
            dec edi                     ; edi = -1
                next_function_loop:
                        inc edi                                         ; increment function counter
                        mov esi, [ebx + edi * 4]         ; esi = relative offset of current function name
                        add esi, ebp                                 ; esi = absolute addr of current function name
                        cdq                                                 ; dl will hold hash (we know eax is small)
                    ;print
                        push esi
                        lea eax, param
                        push eax
                        call dword ptr[printf]
                        add esp, 8
            ;loop
            jmp next_function_loop
        }
}
雪    币: 83
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kenikehan 2012-3-11 11:48
8
0
首先说明,打印函数名时要按导出表结构体中的NumberofNames字段限定循环次数吧,否则运行出错,除非你在动态调试中在出错前观察输出。
然后我看了一下代码估计发现问题真正所在了,请看以下模块:
   ; find base addr of kernel32.dll
      mov ebx, fs:[edx + 0x30]   ; ebx = address of PEB
      mov ecx, [ebx + 0x0c]     ; ecx = pointer to loader data
      mov ecx, [ecx + 0x1c]     ; ecx = first entry in initialisation order list
      mov ecx, [ecx]         ; ecx = second entry in list (kernel32.dll)       mov ebp, [ecx + 0x08]     ; ebp = base address of kernel32.dll

红色代码部分出纰漏了(我看下书,其实书上就出错了,书上关于模块初始化链表中的模块顺序有错吧,但论坛上未曾找到这方面的讨论)
我们先分析下,用pe工具导入表查看ntdl.dll ,kenelbase.dll,  kenenl32.dll我们可以发现kenenl32.dll依赖于kenelbase.dll和ntdl.dll ,kenelbase.dll依赖于ntdl.dll ,就这方面依赖关系来看,初始化链表顺序正确的应该是1.ntdl.dll -->2.kenelbase.dll--> 3.kenenl32.dll
这样按书上的shellcode我们其实索引到的是第二个模块kenelbase.dll(pe工具看到该模块实现了LoadLibraryExA和LoadLibraryExW函数,无LoadLibraryA函数,这印证了我们的函数名输出情况)
另外,从动态调试的M窗口中我们可以看到实际的kenelbase.dll模块地址与书上shellcode得到的所谓kenel32.dll模块地址吻合。
kenel32.dll中导出的LoadLibraryExA/W其实是映射了kenelbase中的函数实现,然后我估计LoadLibraryA的实现是kenel32.dll模块中在LoadLibraryExA基础上实现的,所以要打印出LoadLibraryA我们得索引到真正的kenel32.dll。
这样我们修改代码如下,
   ; find base addr of kernel32.dll
      mov ebx, fs:[edx + 0x30]   ; ebx = address of PEB
      mov ecx, [ebx + 0x0c]     ; ecx = pointer to loader data
      mov ecx, [ecx + 0x1c]     ; ecx = first entry in initialisation order list
      mov ecx, [ecx]
      mov ecx, [ecx]         ; ecx = second entry in list (kernel32.dll)
     mov ebp, [ecx + 0x08]     ; ebp = base address of kernel32.dll
这样调试成功
雪    币: 959
活跃值: (66)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ybhdgggset 2012-3-11 12:03
9
0
雪    币: 83
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
kenikehan 2012-3-11 12:16
10
0
果然是这样啊,当初我还搜了下论坛都没人提这个,我还不放心呢,可是调试结果就是那样,就这么按实际情况过去了,
再次拜谢楼上了
但愿在第二版的时候对这个由系统版本引起的问题稍带提醒一下
雪    币: 202
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ccqmpux 2012-3-11 19:05
11
0
十分感谢~

p.s.我就是debug之间看的,没管运行的错误。
雪    币: 190
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
kxzjchen 2012-3-13 19:49
12
0
[QUOTE=ccqmpux;1052134]我肯定遍历了,我贴下代码吧,就是基于原书章节改的,我都把hash去掉了。
#include <stdio.h>
char param[] = "%s\n";
int main()
{       
        _asm{
                        CLD                                        ; clear flag DF
                        ;store hash
                        push ...[/QUOTE]

兄台,敢问call dword ptr[printf]这句是什么意思,你怎么可以就调用成功了,而我的总是地址溢出了
如下图:
求解释啊
上传的附件:
雪    币: 20
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
aliarthas 2015-7-21 20:02
13
0
留下出问题了再看
游客
登录 | 注册 方可回帖
返回