把合天网安实验室的逆向做了一遍。
逆向 100
Description
看你的咯,移动安全大神(逆向 100, 已解决 534)
题目描述: dex2jar 是我们的好朋友
相关附件: rev100.zip
Solution
$ file rev100
rev100: Zip archive data, at least v2.0 to extract
可以判断出其实给的文件是个 apk,根据提示用 dex2jar 可以做。我这里用 jadx 反编译:
package ctf.crackme;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class FlagActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flag);
String flag = "";
int[] d = new int[]{102, 108, 97, 103, 123, 119, 52, 110, 110, 52, 95, 106, 52, 114, 95, 109, 121, 95, 100, 51, 120, 125};
for (int i = 0; i < 22; i++) {
flag = flag.concat(String.valueOf((char) d[i]));
}
((TextView) findViewById(R.id.flagText)).setText(flag);
}
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.flag, menu);
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
直接把数组 d 的值转字符就完事了:
#!/usr/bin/env python
enc = [102, 108, 97, 103, 123, 119, 52, 110, 110, 52, 95, 106, 52, 114, 95, 109, 121, 95, 100, 51, 120, 125]
flag = ''
for i in range(len(enc)):
flag += chr(enc[i])
print flag
# flag{w4nn4_j4r_my_d3x}
逆向 200
Description
做题累了玩个游戏吧(逆向 200, 已解决 309)
题目描述: pwd1_pwd2
相关附件: rev200.exe
Solution
$ file rev200.exe
rev200.exe: PE32 executable (console) Intel 80386 (stripped to external PDB), for MS Windows
程序加了 tls,但对逆向没有什么影响。直接上 OD 调:
00401B33 |. 83EC 08 sub esp,0x8
00401B36 |. A1 8CAD4000 mov eax,dword ptr ds:[0x40AD8C] ; ||||
00401B3B |. 890424 mov dword ptr ss:[esp],eax ; ||||
00401B3E |. E8 4D5F0000 call <jmp.&msvcrt.puts> ; |||\puts
00401B43 |. 8D85 A9FEFFFF lea eax,dword ptr ss:[ebp-0x157] ; |||
00401B49 |. 894424 04 mov dword ptr ss:[esp+0x4],eax ; |||
00401B4D |. C70424 209040>mov dword ptr ss:[esp],re200_no.00409020 ; |||ASCII "%20s"
00401B54 |. E8 2F5F0000 call <jmp.&msvcrt.scanf> ; ||\scanf
00401B59 |. 8D85 BDFEFFFF lea eax,dword ptr ss:[ebp-0x143] ; ||
00401B5F |. 894424 04 mov dword ptr ss:[esp+0x4],eax ; ||
00401B63 |. 8D85 A9FEFFFF lea eax,dword ptr ss:[ebp-0x157] ; ||
00401B69 |. 890424 mov dword ptr ss:[esp],eax ; ||
00401B6C |. E8 275F0000 call <jmp.&msvcrt.strcmp> ; |\strcmp
00401B71 |. 85C0 test eax,eax ; |
00401B73 |. 75 18 jnz short re200_no.00401B8D ; |
00401B75 |. C70424 269140>mov dword ptr ss:[esp],re200_no.00409126 ; |ASCII "You passed level1!"
00401B7C |. E8 0F5F0000 call <jmp.&msvcrt.puts> ; \puts
00401B81 |. C70424 000000>mov dword ptr ss:[esp],0x0
00401B88 |. E8 5DFAFFFF call re200_no.004015EA
00401B8D |> B8 00000000 mov eax,0x0
00401B92 |. 8D65 F8 lea esp,[local.2]
00401B95 |. 59 pop ecx ; msvcrt.77558E62
00401B96 |. 5B pop ebx
00401B97 |. 5D pop ebp
00401B98 |. 8D61 FC lea esp,dword ptr ds:[ecx-0x4]
00401B9B \. C3 retn
第一个 check 很容易找到 passwd:
堆栈地址=0028FD75, (ASCII "r0b0RUlez!")
eax=00000001
第二个 check 有个 int3
反调试:
004015EA /$ 55 push ebp
004015EB |. 89E5 mov ebp,esp
004015ED |. 83EC 18 sub esp,0x18
004015F0 |. 837D 08 09 cmp [arg.1],0x9
004015F4 |. 7F 11 jg short re200_no.00401607
004015F6 |. 8345 08 01 add [arg.1],0x1
004015FA |. 8B45 08 mov eax,[arg.1]
004015FD |. 890424 mov dword ptr ss:[esp],eax ; re200_no.00401619
00401600 |. E8 E5FFFFFF call re200_no.004015EA
00401605 |. EB 1E jmp short re200_no.00401625
00401607 |> A1 90AD4000 mov eax,dword ptr ds:[0x40AD90] ; |
0040160C |. 890424 mov dword ptr ss:[esp],eax ; |re200_no.00401619
0040160F |. E8 7C640000 call <jmp.&msvcrt.puts> ; \puts
00401614 |. E8 00000000 call re200_no.00401619
00401619 |$ 58 pop eax ; 0028FDD5
0040161A |. A3 A8AD4000 mov dword ptr ds:[0x40ADA8],eax ; re200_no.00401619
0040161F |. CC int3
00401620 |. B8 00000000 mov eax,0x0
00401625 |> C9 leave
00401626 \. C3 retn
新增的 AddVectoredExceptionHandler
这个 API 将一个指向函数的指针作为参数,把这个函数的地址添加到已注册的异常处理程序链表中。那么这里的 int 3
异常会交给异常处理程序链表中第一个处理函数处理,假如调试器处理这个异常,我们就到不了那里了,所以 OD 的设置一定要忽略所有异常,让程序或系统自己处理。
00401B0E |. 83EC 04 sub esp,0x4
00401B11 |. 895C24 04 mov dword ptr ss:[esp+0x4],ebx ; |
00401B15 |. 890424 mov dword ptr ss:[esp],eax ; |re200_no.00401619
00401B18 |. A1 60B14000 mov eax,dword ptr ds:[<&KERNEL32.GetProcAddress>] ; |
00401B1D |. FFD0 call eax ; \GetProcAddress
00401B1F |. 83EC 08 sub esp,0x8
00401B22 |. C74424 04 7F1>mov dword ptr ss:[esp+0x4],re200_no.0040157F
00401B2A |. C70424 010000>mov dword ptr ss:[esp],0x1
00401B31 |. FFD0 call eax ; re200_no.00401619
00401B33 |. 83EC 08 sub esp,0x8
00401B36 |. A1 8CAD4000 mov eax,dword ptr ds:[0x40AD8C] ; ||||
00401B3B |. 890424 mov dword ptr ss:[esp],eax ; ||||re200_no.00401619
00401B3E |. E8 4D5F0000 call <jmp.&msvcrt.puts> ; |||\puts
重新调试一遍,可以在 1AF9
处看到程序将 AddVectoredExceptionHandler
的地址(DS:0x40ADAC
存放的是字符串 AddVectoredExceptionHandler
)从 kernel32.dll
中取出,并且将 0040157F
函数注册到了这个地方:
00401AF9 |. 8B1D ACAD4000 MOV EBX,DWORD PTR DS:[0x40ADAC] ; |
00401AFF |. A1 9CAD4000 MOV EAX,DWORD PTR DS:[0x40AD9C] ; |
00401B04 |. 890424 MOV DWORD PTR SS:[ESP],EAX ; |
00401B07 |. A1 5CB14000 MOV EAX,DWORD PTR DS:[<&KERNEL32.GetModuleHandleA>] ; |
00401B0C |. FFD0 CALL EAX ; \GetModuleHandleA
00401B0E |. 83EC 04 SUB ESP,0x4
00401B11 |. 895C24 04 MOV DWORD PTR SS:[ESP+0x4],EBX ; |
00401B15 |. 890424 MOV DWORD PTR SS:[ESP],EAX ; |
00401B18 |. A1 60B14000 MOV EAX,DWORD PTR DS:[<&KERNEL32.GetProcAddress>] ; |
00401B1D |. FFD0 CALL EAX ; \GetProcAddress
00401B1F |. 83EC 08 SUB ESP,0x8
00401B22 |. C74424 04 7F1>MOV DWORD PTR SS:[ESP+0x4],rev200.0040157F
00401B2A |. C70424 010000>MOV DWORD PTR SS:[ESP],0x1
00401B31 |. FFD0 CALL EAX
找到 157F
处,删除分析后就能看到代码:
0040157F 55 push ebp
00401580 89E5 mov ebp,esp
00401582 83EC 38 sub esp,0x38
00401585 8B45 08 mov eax,dword ptr ss:[ebp+0x8]
00401588 8B40 04 mov eax,dword ptr ds:[eax+0x4] ; ntdll_12.77DF9D4C
0040158B 8B80 B8000000 mov eax,dword ptr ds:[eax+0xB8]
00401591 8945 F4 mov dword ptr ss:[ebp-0xC],eax
00401594 8B45 F4 mov eax,dword ptr ss:[ebp-0xC] ; re200_no.00409020
00401597 8B15 A8AD4000 mov edx,dword ptr ds:[0x40ADA8] ; re200_no.00401619
0040159D 83C2 06 add edx,0x6
004015A0 39D0 cmp eax,edx ; msvcrt._iob
004015A2 75 38 jnz short re200_no.004015DC
004015A4 8D45 E0 lea eax,dword ptr ss:[ebp-0x20]
004015A7 894424 04 mov dword ptr ss:[esp+0x4],eax
004015AB C70424 20904000 mov dword ptr ss:[esp],re200_no.00409020 ; ASCII "%20s"
004015B2 E8 D1640000 call <jmp.&msvcrt.scanf>
004015B7 A1 98AD4000 mov eax,dword ptr ds:[0x40AD98]
004015BC 894424 04 mov dword ptr ss:[esp+0x4],eax
004015C0 8D45 E0 lea eax,dword ptr ss:[ebp-0x20]
004015C3 890424 mov dword ptr ss:[esp],eax
004015C6 E8 7CFFFFFF call re200_no.00401547
在 1547
处,可以看到是对内存中长度为 8 的一串数据与 2 进行了异或:
00401547 55 push ebp
00401548 89E5 mov ebp,esp
0040154A EB 22 jmp short re200_no.0040156E
0040154C 8B45 08 mov eax,dword ptr ss:[ebp+0x8]
0040154F 0FB610 movzx edx,byte ptr ds:[eax]
00401552 8B45 0C mov eax,dword ptr ss:[ebp+0xC]
00401555 0FB600 movzx eax,byte ptr ds:[eax]
00401558 83F0 02 xor eax,0x2
0040155B 38C2 cmp dl,al
0040155D 74 07 je short re200_no.00401566
0040155F B8 01000000 mov eax,0x1
00401564 EB 17 jmp short re200_no.0040157D
00401566 8345 08 01 add dword ptr ss:[ebp+0x8],0x1
0040156A 8345 0C 01 add dword ptr ss:[ebp+0xC],0x1
0040156E 8B45 0C mov eax,dword ptr ss:[ebp+0xC]
00401571 0FB600 movzx eax,byte ptr ds:[eax]
00401574 3C 02 cmp al,0x2
00401576 ^ 75 D4 jnz short re200_no.0040154C
00401578 B8 00000000 mov eax,0x0
0040157D 5D pop ebp ; re200_no.004015CB
0040157E C3 retn
在堆栈部分可以看到存储的地址:
0028F62C /0028F66C
0028F630 |004015CB 返回到 re200_no.004015CB 来自 re200_no.00401547
0028F634 |0028F64C 输入字符串地址
0028F638 |0028FDCC 用来比较的字符串的地址
0028F63C |00000000
0028F640 |00000000
0028F644 |00000000
0028F648 |00000000
在数据窗口跟随得到数据:
0028FDCC 75 31 6E 6E 66 32 6C 67 02 50 6C 65 61 73 65 20 u1nnf2lgPlease
0028FDDC 65 6E 74 65 72 20 74 68 65 20 73 65 63 6F 6E 64 enter the second
写个脚本逆出结果:
#!/usr/bin/env python
enc = [0x75, 0x31, 0x6E, 0x6E, 0x66, 0x32, 0x6C, 0x67, 0x02]
res = ''
for i in range(len(enc)):
res += chr(enc[i] ^ 0x02)
print res
# w3lld0ne
逆向 300
Description
ELF(逆向 300, 已解决 139)
题目描述: 靠,我这儿也没有 IDA 啊
相关附件: rev300.zip
Solution
$ file rev300
rev300: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=a93ffe39302e19ef5184a1d86b720b11a7a97941, stripped
总共有两个 check:
int __cdecl main(int a1, char **a2)
{
if ( a1 > 1 && sub_8048414(a2[1], 0) )
{
puts("Access granted");
sub_8048538((int)a2[1]);
}
else
{
puts("Access denied");
}
return 0;
}
第一个是对程序参数的的一个比较,一个递归的函数:
signed int __cdecl sub_8048414(_BYTE *a1, int a2)
{
signed int result; // eax
switch ( a2 )
{
case 0:
if ( *a1 == 'i' )
goto LABEL_19;
result = 0;
break;
case 1:
if ( *a1 == 'e' )
goto LABEL_19;
result = 0;
break;
case 3:
if ( *a1 == 'n' )
goto LABEL_19;
result = 0;
break;
case 4:
if ( *a1 == 'd' )
goto LABEL_19;
result = 0;
break;
case 5:
if ( *a1 == 'a' )
goto LABEL_19;
result = 0;
break;
case 6:
if ( *a1 == 'g' )
goto LABEL_19;
result = 0;
break;
case 7:
if ( *a1 == 's' )
goto LABEL_19;
result = 0;
break;
case 9:
if ( *a1 == 'r' )
LABEL_19:
result = sub_8048414(a1 + 1, 7 * (a2 + 1) % 11);
else
result = 0;
break;
default:
result = 1;
break;
}
return result;
}
第二个是把正确的输入和内存中的数据进行异或:
int __cdecl sub_8048538(int a1)
{
int v2[33]; // [esp+18h] [ebp-A0h]
int i; // [esp+9Ch] [ebp-1Ch]
qmemcpy(v2, &unk_8048760, sizeof(v2));
for ( i = 0; i <= 32; ++i )
putchar(v2[i] ^ *(char *)(a1 + i % 8));
return putchar(10);
}
脚本如下:
#!/usr/bin/env python
enc = [0x0000000F, 0x0000001F, 0x00000004, 0x00000009, 0x0000001C, 0x00000012, 0x00000042, 0x00000009, 0x0000000C, 0x00000044, 0x0000000D, 0x00000007, 0x00000009, 0x00000006, 0x0000002D, 0x00000037, 0x00000059, 0x0000001E, 0x00000000, 0x00000059, 0x0000000F, 0x00000008, 0x0000001C, 0x00000023, 0x00000036, 0x00000007, 0x00000055, 0x00000002, 0x0000000C, 0x00000008, 0x00000041, 0x0000000A, 0x00000014]
key = ''
i = 0
for j in range(8):
if i == 0:
key += 'i'
if i == 1:
key += 'e'
if i == 3:
key += 'n'
if i == 4:
key += 'd'
if i == 5:
key += 'a'
if i == 6:
key += 'g'
if i == 7:
key += 's'
if i == 9:
key += 'r'
i = 7 * (i + 1) % 11
print key
flag = ''
for i in range(len(enc)):
flag += chr(enc[i] ^ ord(key[i % 8]))
print flag
对参数的求解也可以用 angr 来完成:
#!/usr/bin/env python
import angr
import claripy
p = angr.Project('./rev300')
flag = claripy.BVS('flag', 50 * 8)
state = p.factory.entry_state(args=['./rev300', flag])
sim = p.factory.simgr(state)
sim.explore(find=0x080485E0, avoid=0x080485FE)
print(sim.found[0].solver.eval(flag, cast_to=bytes))
References
https://www.52pojie.cn/forum.php?mod=viewthread&tid=530793
https://blog.csdn.net/xiangshangbashaonian/article/details/82953042
https://docs.microsoft.com/en-us/windows/win32/debug/using-a-vectored-exception-handler