Reserving.Kr writeup
Easy Crack
Easy Keygen
Replace
Easy_ELF
Reversing.Kr writeup
这个网站http://reversing.kr 学习逆向很不错。各个平台的逆向都有,最近在慢慢的刷这些题
Easy Crack
看名字就知道很简单,PEID查壳,拖入OD,找到关键代码
0040109B|.8B7C2470 mov edi,dword ptr ss:[esp+0x70];|user32.76D1D2B3
0040109F|.8D442408 lea eax,dword ptr ss:[esp+0x8];|
004010A3|.50 push eax ;|Buffer=0000000D
004010A4|.68 E8030000 push 0x3E8;|ControlID=3E8(1000.)
004010A9|.57 push edi ;|hWnd =0060157E(‘Easy CrackMe‘,class=‘#32770‘)
004010AA|. FF15 9C504000 call dword ptr ds:[<&USER32.GetDlgItemTe>; \GetDlgItemTextA
004010B0|.807C240561 cmp byte ptr ss:[esp+0x5],0x61;比较1
004010B5757E jnz shortEasy_Cra.00401135
004010B7|.6A02 push 0x2
004010B9|.8D4C240A lea ecx,dword ptr ss:[esp+0xA]
004010BD|.6878604000 push Easy_Cra.00406078; ASCII "5y"
004010C2|.51 push ecx ; user32.76D0B7D6
004010C3|. E8 88000000 call Easy_Cra.00401150
004010C8|.83C40C add esp,0xC
004010CB|.85C0 test eax,eax ;比较2
004010CD7566 jnz shortEasy_Cra.00401135
004010CF|.53 push ebx ;Easy_Cra.00401020
004010D0|.56 push esi ;Easy_Cra.00401020
004010D1|. BE 6C604000 mov esi,Easy_Cra.0040606C; ASCII "R3versing"
004010D6|.8D442410 lea eax,dword ptr ss:[esp+0x10]
004010DA|>8A10/mov dl,byte ptr ds:[eax]
004010DC|.8A1E|mov bl,byte ptr ds:[esi]
004010DE|.8ACA|mov cl,dl
004010E0|.3AD3|cmp dl,bl
004010E2|.751E|jnz shortEasy_Cra.00401102
004010E4|.84C9|test cl,cl
004010E6|.7416|je shortEasy_Cra.004010FE
004010E8|.8A5001|mov dl,byte ptr ds:[eax+0x1]
004010EB|.8A5E01|mov bl,byte ptr ds:[esi+0x1]
004010EE|.8ACA|mov cl,dl
004010F0|.3AD3|cmp dl,bl
004010F2|.750E|jnz shortEasy_Cra.00401102
004010F4|.83C002|add eax,0x2
004010F7|.83C602|add esi,0x2
004010FA|.84C9|test cl,cl
004010FC|.^75 DC \jnz shortEasy_Cra.004010DA
004010FE|>33C0 xor eax,eax
00401100|. EB 05 jmp shortEasy_Cra.00401107
00401102|>1BC0 sbb eax,eax
00401104|.83D8 FF sbb eax,-0x1
00401107|>5E pop esi ;Easy_Cra.00401020
00401108|.5B pop ebx ;Easy_Cra.00401020
00401109|.85C0 test eax,eax ;比较3
0040110B7528 jnz shortEasy_Cra.00401135
0040110D|.807C240445 cmp byte ptr ss:[esp+0x4],0x45;比较4
004011127521 jnz shortEasy_Cra.00401135
00401114|.6A40 push 0x40;/Style= MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00401116|.6858604000 push Easy_Cra.00406058;|Title="EasyCrackMe"
0040111B|.6844604000 push Easy_Cra.00406044;|Text="Congratulation !!"
00401120|.57 push edi ;|hOwner =0060157E(‘Easy CrackMe‘,class=‘#32770‘)
00401121|. FF15 A0504000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
00401127|.6A00 push 0x0;/Result=0x0
00401129|.57 push edi ;|hWnd =0060157E(‘Easy CrackMe‘,class=‘#32770‘)
0040112A|. FF15 A4504000 call dword ptr ds:[<&USER32.EndDialog>]; \EndDialog
00401130|.5F pop edi
00401131|.83C464 add esp,0x64
00401134|. C3 retn
00401135|>6A10 push 0x10;/Style= MB_OK|MB_ICONHAND|MB_APPLMODAL
00401137|.6858604000 push Easy_Cra.00406058;|Title="EasyCrackMe"
0040113C|.6830604000 push Easy_Cra.00406030;|Text="Incorrect Password"
00401141|.57 push edi ;|hOwner =0060157E(‘Easy CrackMe‘,class=‘#32770‘)
00401142|. FF15 A0504000 call dword ptr ds:[<&USER32.MessageBoxA>>; \MessageBoxA
输入Ea5yR3versing(这就是flag)
看到这句话
也就是说,当运行到这里的时候,我们的输入已经入栈,首字符‘E‘存在[esp+0x4]
。
接下来上面的代码就是不断判断这个字符串各个位置的字符是否和程序中预先写好的一样,一旦有一个地方不一样,就直接跳转到00401135
去弹出Incorrect Password窗口。根据程序中硬编码的字符串,拼接出来正确的字符串就是Ea5yR3versing
。
当然,这道题直接nop掉所有相关跳转也可以暴力破解。
Easy Keygen
win32的程序,无壳,拖入IDA,反编译,看看大概逻辑
int __cdecl main(int argc,constchar**argv,constchar**envp)
{
signedint v3;// [email protected]
signedint i;// [email protected]
int result;// [email protected]
char v6;// [sp+Ch] [bp-130h]@1
char v7;// [sp+Dh] [bp-12Fh]@1
char v8;// [sp+Eh] [bp-12Eh]@1
char v9;// [sp+10h] [bp-12Ch]@1
char v10;// [sp+11h] [bp-12Bh]@1
__int16 v11;// [sp+71h] [bp-CBh]@1
char v12;// [sp+73h] [bp-C9h]@1
char v13;// [sp+74h] [bp-C8h]@1
char v14;// [sp+75h] [bp-C7h]@1
__int16 v15;// [sp+139h] [bp-3h]@1
char v16;// [sp+13Bh] [bp-1h]@1
v9 =0;
v13 =0;
memset(&v10,0,0x60u);
v11 =0;
v12 =0;
memset(&v14,0,0xC4u);
v15 =0;
v16 =0;
v6 =16;
v7 =32;
v8 =48;
sub_4011B9(aInputName);
scanf(aS,&v9);
v3 =0;
for( i =0; v3 <(signedint)strlen(&v9);++i )
{
if( i >=3)
i =0;
sprintf(&v13, aS02x,&v13,*(&v9 + v3++)^*(&v6 + i));// aS02x==>%s%02X,指定了格式,表示长度为两位的16进制显示,并且如果有字母,字母大写
}
memset(&v9,0,0x64u);
sub_4011B9(aInputSerial);
scanf(aS,&v9);
if(!strcmp(&v9,&v13))
{
sub_4011B9(aCorrect);
result =0;
}
else
{
sub_4011B9(aWrong);
result =0;
}
return result;
}
注意sprintf的参数aS02x
,通过OD的动态调试,我们可以看到这个参数的具体意思
给出通过name计算serial的注册机代码
name = raw_input()
ordname =[]
for i in range(len(name)):
ordname.append(ord(name[i]))
i =0
v6 =[16,32,48]
serial =[]
for v3 in range(len(ordname)):
if(i>=3):
i =0
serial.append(ordname[v3]^v6[i])
i+=1
flag =""
for i in range(len(serial)):
flag += chr(serial[i])
print(flag.encode("hex").upper())
这个题目的要求是给一个serial,求出name,根据上面的代码,给出通过serial计算name的脚本
serial ="5B134977135E7D13"
serial =[ord(i)for i in serial.lower().decode("hex")]
name =[]
v6 =[16,32,48]
i =0
for v3 in range(len(serial)):
if(i>=3):
i =0
name.append(serial[v3]^v6[i])
i+=1
print(name)
namestr =""
for j in range(len(name)):
namestr+=chr(name[j])
print(namestr)
计算结果K3yg3nm3
Replace
32位的无壳程序,先用IDA看看逻辑和一些字符串
发现有Correct!
字符串,追踪交叉引再反编译,这段代码并看不懂。但是我们可以知道了这个关键字符串的地址
在OD中找到这段代码
这是关键代码
00401050.6A00 push 0x0;/IsSigned= FALSE
00401052.6A00 push 0x0;|pSuccess = NULL
00401054.68 EA030000 push 0x3EA;|ControlID=3EA(1002.)
00401059.56 push esi ;|hWnd =004010B0
0040105A. FF15 9C504000 call dword ptr ds:[<&USER32.GetDlgItemIn>; \GetDlgItemInt 调用API函数取得输入的内容
00401060. A3 D0844000 mov dword ptr ds:[0x4084D0],eax
00401065. E8 05360000 call Replace.0040466F;可以对ds:[0x4084D0]的内容做一个转换
0040106A.33C0 xor eax,eax
0040106C E9 1F360000 jmp Replace.00404690;无条件跳转
00401071 EB 11 jmp shortReplace.00401084
00401073.683460400>ascii "h4`@",0;Correct!
00401078.68 E9030000 push 0x3E9;|ControlID=3E9(1001.)
0040107D.56 push esi ;|hWnd =004010B0
0040107E. FF15 A0504000 call dword ptr ds:[<&USER32.SetDlgItemTe>; \SetDlgItemTextA
在在输出正确之前,有两个无条件跳转,先看第一个,这是跳转之后的代码
00404690> \A1 D0844000 mov eax,dword ptr ds:[0x4084D0]
00404695.689F464000 push Replace.0040469F
0040469A. E8 EAFFFFFF call Replace.00404689
0040469F. C705 6F464000>mov dword ptr ds:[0x40466F],0xC39000C6
004046A9. E8 C1FFFFFF call Replace.0040466F;这里程序报错了
004046AE.40 inc eax
004046AF. E8 BBFFFFFF call Replace.0040466F
004046B4. C705 6F464000>mov dword ptr ds:[0x40466F],0x6E8
004046BE.58 pop eax ;Replace.0040469F
004046BF. B8 FFFFFFFF mov eax,-0x1
004046C4.^ E9 A8C9FFFF jmp Replace.00401071
经过测试,程序在执行004046A9的call Replace.0040466F报错,进入这个函数
0040466F C600 90 mov byte ptr ds:[eax],0x90
00404672 C3 retn
这个0x90就是nop指令的16进制表示,也就是说这个指令将ds:[eax]中的指令nop掉,注意上段代码004046C4 .^ E9 A8C9FFFF jmp Replace.00401071
就是跳转回这里执行
这就是我上述的第二个无条件跳转点,只要我们用Replace.0040466F将这里的jmp指令nop掉就可以输出Correct了,所以所以说正好调用上这个Replace.0040466F
函数。那么接下来我们要解决的问题就是怎么让eax=00401071。追踪eax的调用过程,首先是调用GetDlgItemInt
API函数取得输入内容放在eax,并将eax赋给 ds:[0x4084D0]。接下来调用Replace.0040466F
函数,这个函数对实现了对内存ds:[0x4084D0]的内容进行了某种转换,经过测试,我们可以认为这种转化是输入的值加上0x601605CB
,这是输入值为0时,经过函数变换后ds:[0x4084D0]的值
此外此函数还对eax加一。
接着是第一个无条件跳转指令,跳转到00404690
执行mov eax,dword ptr ds:[0x4084D0]
对eax赋值,接着就是进入Replace.0040466F
,执行这句话0040466F C600 90 mov byte ptr ds:[eax],0x90
。如果这个的eax=00401071就对了,也就是说我们要这个公式成立input+0x601605CB=0x00401071
。如果上述公式成立,那么input一定是负数,但是经过测试此程序只可以输入正数。考虑eax是32位的,也就是说如果input+0x601605CB=0x100401071
的话,会产生进位,但是eax=0x00401071。所以input=0x100401071-0x601605CB=2687109798
,验证一下,输入上述值是正确的
Easy_ELF
名字已经说的很明确了,Linux下的ELF文件逆向。
逻辑很简单,就是输入字符串,经过变换之后与已知值进行比较。
输入的值L1NUX