Reverse
bbvvmm
用ida打开 可以发现程序读入了用户名和密码,然后对用户名和密码进行了加密,如果用户名和密码校验正确,那么就cat flag
首先是用户名,用户名先进行一层加密,后进行sm4加密,最后进行变表base64转换为了一串密文
首先解决base64:
import base64
tab2 = "IJLMNOPKABDEFGHCQRTUVWXSYZbcdefa45789+/6ghjklmnioprstuvqwxz0123y="
tab1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
s2 = "RVYtG85NQ9OPHU4uQ8AuFM+MHVVrFMJMR8FuF8WJQ8Y="
s1 = ""
for c in s2:
for i in range(len(tab2)):
if(tab2[i] == c):
s1 += tab1[i]
break
print(base64.b64decode(s1))
得到“EF468DBAF985B2509C9E200CF3525AB6”
然后是sm4加密算法,直接在网上找轮子
解密得到“36 32 36 31 36 34 37 32 36 35 37 32 33 31 33 32”
最后
两次转化成ascii
第一次62 61 54 72 65 72 31 32
第二次b a d r e r 1 2
然后就得到了用户名
对于密码,并不清楚这个密码使用了什么加密算法,只清楚这是一个虚拟机,有几百个操作数,好像是对密码进行了某种运算,最后将运算结果保存到内存的某个地方,如果这个内存数据为0,那么密码便正确
直接开ida动态远程调试:
能找到一个类似于栈的结构(一直+4 -4),在内存中找到这个栈对应的位置
通过不断地循环fastcall,看到栈中出现了我刚刚输入的字符串,并且旁边是一堆奇特字符串,而且长度也是六位,于是尝试交上去,成功
getshell的时候:输入密码之后不能直接按回车键,这样会多输入一个 \n,而应该ctrl+d,输入文本中断符,然后拿到flag
Strange_Int
打国赛的时候没做出来这道题,现在看了题解来补一补
思路
开始
以前写过FAT16的模拟程序,看到这个文件第一想法是这是一个DBR
第一行的 jmp 就是 jump 到这个命令的下一个命令。。
seg000:0000 jmp far ptr 7C0h:5
seg000:0005 ; ---------------------------------------------------------------------------
seg000:0005 mov ax, cs
seg000:0007 mov ds, ax
seg000:0009 mov ss, ax
seg000:000B mov sp, 400h
seg000:000E cld
seg000:000F mov ax, 3
seg000:0012 int 10h ; - VIDEO - SET VIDEO MODE
seg000:0012 ; AL = mode
seg000:0014 mov dx, 0
seg000:0017 mov cx, 2
seg000:001A mov ax, 1000h
seg000:001D mov es, ax
seg000:001F assume es:nothing
seg000:001F xor bx, bx
seg000:0021 mov ax, 228h
seg000:0024 int 13h ; DISK - READ SECTORS INTO MEMORY
seg000:0024 ; AL = number of sectors to read, CH = track, CL = sector
seg000:0024 ; DH = head, DL = drive, ES:BX -> buffer to fill
seg000:0024 ; Return: CF set on error, AH = status, AL = number of sectors read
seg000:0026 jnb short loc_2A
seg000:0028
seg000:0028 loc_28: ; CODE XREF: seg000:loc_28↓j
seg000:0028 jmp short loc_28
seg000:002A ; ---------------------------------------------------------------------------
seg000:002A
seg000:002A loc_2A: ; CODE XREF: seg000:0026↑j
seg000:002A cli
seg000:002B mov ax, 1000h
seg000:002E mov ds, ax
seg000:0030 assume ds:nothing
seg000:0030 xor ax, ax
seg000:0032 mov es, ax
seg000:0034 assume es:nothing
seg000:0034 mov cx, 2000h
seg000:0037 sub si, si
seg000:0039 sub di, di
seg000:003B rep movsb
seg000:003D mov ax, 7C0h
seg000:0040
seg000:0040 loc_40: ; DATA XREF: seg000:0012↑r
seg000:0040 mov ds, ax
seg000:0042 assume ds:nothing
seg000:0042 lidt fword ptr ds:6Fh
seg000:0047 lgdt fword ptr ds:75h
seg000:004C
seg000:004C loc_4C: ; DATA XREF: seg000:0024↑r
seg000:004C mov ax, 1
seg000:004F lmsw ax
seg000:0052 jmp far ptr 8:0
然后就跳转到一个神秘的鬼地方去了
程序大概是把ebx置0了,然后作为计数变量,一共循环了10h次
把一堆数送到了内存中,经高人指点,这堆数属于中断向量
(也就是VM里面的操作数,对应相应的操作)
seg000:000001FE ; ---------------------------------------------------------------------------
seg000:000001FE push ebp
seg000:000001FF stosb
seg000:00000200 mov eax, 10h
seg000:00000205 mov ds, eax
seg000:00000207 assume ds:nothing
seg000:00000207 lss esp, large ds:0B5Ch
seg000:0000020E call sub_28B
seg000:00000213 call sub_283
seg000:00000218 mov eax, 10h ; DATA XREF: sub_28B+27↓r
seg000:0000021D mov ds, eax
seg000:0000021F mov es, eax
seg000:00000221 assume es:nothing
seg000:00000221 mov fs, eax ; DATA XREF: sub_283↓r
seg000:00000223 assume fs:nothing
seg000:00000223 mov gs, eax
seg000:00000225 assume gs:nothing
seg000:00000225
seg000:00000225 loc_225: ; DATA XREF: sub_28B+11↓o
seg000:00000225 lss esp, large ds:0B5Ch
seg000:0000022C xor ebx, ebx
seg000:0000022E
seg000:0000022E loc_22E: ; CODE XREF: seg000:0000025D↓j
seg000:0000022E nop
seg000:0000022F cmp ebx, 10h
seg000:00000232 jge short loc_25F
seg000:00000234 mov eax, 80000h
seg000:00000239 lea edx, ds:0D08h[ebx*4] ;这个内存里面全部存的0
seg000:00000240 mov edx, [edx]
seg000:00000242 mov ax, dx
seg000:00000245 mov dx, 8E00h
seg000:00000249 mov ecx, 21h ; '!' ;21h
seg000:0000024E add ecx, ebx ;21h + ebx,
;也就是把21h开始的10h个数作为操作数
seg000:00000250 lea esi, ds:128h[ecx*8]
seg000:00000257 mov [esi], eax
seg000:00000259 mov [esi+4], edx
seg000:0000025C inc ebx
seg000:0000025D jmp short loc_22E
seg000:0000025F ; ---------------------------------------------------------------------------
# 后面是多次中断进行操作
seg000:0000025F
seg000:0000025F loc_25F: ; CODE XREF: seg000:00000232↑j
seg000:0000025F ; seg000:00000266↓j
seg000:0000025F call sub_268
seg000:00000264 int 21h ; DOS -
seg000:00000266 jmp short loc_25F
switch跳转语句
中断之前call的sub_268汇编代码如下:
seg000:00000268 sub_268 proc near ; CODE XREF: seg000:loc_25F↑p
seg000:00000268 mov edi, large ds:0B78h
seg000:0000026E lea edi, ds:0D48h[edi*4]
seg000:00000275 mov eax, [edi]
seg000:00000277 mov large ds:65h, al
seg000:0000027C mov ecx, [edi+4]
seg000:0000027F mov eax, [edi+8]
seg000:00000282 retn
seg000:00000282 sub_268 endp
操作数1被送入内存了
ecx应该是操作数2
eax是操作数3
各个case
汇编
以下是每个操作数对应的操作, 因为所有的操作数是依次出现的 ,所以只需要挨着翻译就好了
seg000:00000D7C ; ---------------------------------------------------------------------------
seg000:00000D7C lea ecx, ds:0B64h[ecx*4]
seg000:00000D83 mov [ecx], eax
seg000:00000D85 jmp loc_EF8
seg000:00000D8A ; ---------------------------------------------------------------------------
seg000:00000D8A lea eax, ds:0B64h[eax*4]
seg000:00000D91 mov eax, [eax]
seg000:00000D93 lea ecx, ds:0B64h[ecx*4]
seg000:00000D9A mov [ecx], eax
seg000:00000D9C jmp loc_EF8
seg000:00000DA1 ; ---------------------------------------------------------------------------
seg000:00000DA1 lea eax, ds:0B64h[eax*4]
seg000:00000DA8 mov eax, [eax]
seg000:00000DAA lea ecx, ds:0B64h[ecx*4]
seg000:00000DB1 lea eax, ds:0D48h[eax*4]
seg000:00000DB8 mov eax, [eax]
seg000:00000DBA mov [ecx], eax
seg000:00000DBC jmp loc_EF8
seg000:00000DC1 ; ---------------------------------------------------------------------------seg000:00000DC1 lea eax, ds:0B64h[eax*4]
seg000:00000DC8 mov eax, [eax]
seg000:00000DCA lea ecx, ds:0B64h[ecx*4]
seg000:00000DD1 mov ecx, [ecx]
seg000:00000DD3 lea ecx, ds:0D48h[ecx*4]
seg000:00000DDA mov [ecx], eax
seg000:00000DDC jmp loc_EF8
seg000:00000DE1 ; ---------------------------------------------------------------------------
seg000:00000DE1 lea eax, ds:0B64h[eax*4]
seg000:00000DE8 mov edx, [eax]
seg000:00000DEA lea ecx, ds:0B64h[ecx*4]
seg000:00000DF1 mov eax, [ecx]
seg000:00000DF3 add eax, edx
seg000:00000DF5 mov [ecx], eax
seg000:00000DF7 jmp loc_EF8
seg000:00000DFC ; ---------------------------------------------------------------------------
seg000:00000DFC lea eax, ds:0B64h[eax*4]
seg000:00000E03 mov edx, [eax]
seg000:00000E05 lea ecx, ds:0B64h[ecx*4]
seg000:00000E0C mov eax, [ecx]
seg000:00000E0E sub eax, edx
seg000:00000E10 mov [ecx], eax
seg000:00000E12 jmp loc_EF8
seg000:00000E17 ; ---------------------------------------------------------------------------
seg000:00000E17 lea eax, ds:0B64h[eax*4]
seg000:00000E1E mov edx, [eax]
seg000:00000E20 lea ecx, ds:0B64h[ecx*4]
seg000:00000E27 mov eax, [ecx]
seg000:00000E29 xor eax, edx
seg000:00000E2B mov [ecx], eax
seg000:00000E2D jmp loc_EF8
seg000:00000E32 ; ---------------------------------------------------------------------------
seg000:00000E32 lea eax, ds:0B64h[eax*4]
seg000:00000E39 mov eax, [eax]
seg000:00000E3B lea edx, ds:0B64h[ecx*4]
seg000:00000E42 mov cl, al
seg000:00000E44 mov eax, [edx]
seg000:00000E46 shl eax, cl
seg000:00000E48 mov [edx], eax
seg000:00000E4A jmp loc_EF8
seg000:00000E4F ; ---------------------------------------------------------------------------
seg000:00000E4F lea eax, ds:0B64h[eax*4]
seg000:00000E56 mov eax, [eax]
seg000:00000E58 lea edx, ds:0B64h[ecx*4]
seg000:00000E5F mov cl, al
seg000:00000E61 mov eax, [edx]
seg000:00000E63 shr eax, cl
seg000:00000E65 mov [edx], eax
seg000:00000E67 jmp loc_EF8
seg000:00000E6C ; ---------------------------------------------------------------------------
seg000:00000E6C lea eax, ds:0B64h[eax*4]
seg000:00000E73 mov eax, [eax]
seg000:00000E75 lea ecx, ds:0B64h[ecx*4]
seg000:00000E7C mov edx, [ecx]
seg000:00000E7E and eax, edx
seg000:00000E80 mov [ecx], eax
seg000:00000E82 jmp short loc_EF8
seg000:00000E84 ; ---------------------------------------------------------------------------
seg000:00000E84 lea eax, ds:0B64h[ecx*4]
seg000:00000E8B mov eax, [eax]
seg000:00000E8D lea ecx, unk_B78
seg000:00000E93 mov [ecx], eax
seg000:00000E95 iret
seg000:00000E96 ; ---------------------------------------------------------------------------
seg000:00000E96 lea eax, ds:0B64h[eax*4]
seg000:00000E9D mov eax, [eax]
seg000:00000E9F test eax, eax
seg000:00000EA1 jnz short loc_EF8
seg000:00000EA3 lea eax, ds:0B64h[ecx*4]
seg000:00000EAA mov eax, [eax]
seg000:00000EAC lea ecx, unk_B78
seg000:00000EB2 mov [ecx], eax
seg000:00000EB4 iret
seg000:00000EB5 ; ---------------------------------------------------------------------------
seg000:00000EB5 lea eax, ds:0B64h[eax*4]
seg000:00000EBC mov eax, [eax]
seg000:00000EBE test eax, eax
seg000:00000EC0 jz short loc_EF8
seg000:00000EC2 lea eax, ds:0B64h[ecx*4]
seg000:00000EC9 mov eax, [eax]
seg000:00000ECB lea ecx, unk_B78
seg000:00000ED1 mov [ecx], eax
seg000:00000ED3 iret
seg000:00000ED4 ; ---------------------------------------------------------------------------
seg000:00000ED4 lea eax, unk_F94
seg000:00000EDA call sub_2EA
seg000:00000EDF hlt
seg000:00000EE0 ; ---------------------------------------------------------------------------
seg000:00000EE0 lea eax, unk_FA0
seg000:00000EE6 call sub_2EA
seg000:00000EEB lea eax, word_FAE
seg000:00000EF1 call sub_2EA
seg000:00000EF6 hlt
seg000:00000EF6 ; ---------------------------------------------------------------------------
seg000:00000EF7 db 0F4h
seg000:00000EF8 ; ---------------------------------------------------------------------------
seg000:00000EF8
seg000:00000EF8 loc_EF8: ; CODE XREF: seg000:00000D85↑j
seg000:00000EF8 ; seg000:00000D9C↑j ...
seg000:00000EF8 lea ecx, unk_B78
seg000:00000EFE mov eax, [ecx]
seg000:00000F00 add eax, 3
seg000:00000F03 mov [ecx], eax
seg000:00000F05 iret
seg000:00000F05 ; ---------------------------------------------------------------------------
翻译后
buf[a] = b
buf[a] = buf[b]
buf[a] = (dword) opt[buf[b]]
(dword) opt[buf[a]] = buf[b]
buf[a] += buf[b]
buf[a] -= buf[b]
buf[a] ^= buf[b]
buf[a] <<= buf[b]
buf[a] >>= buf[b]
buf[a] &= buf[b]
temp = buf[a]
if(buf[b] == 0) temp = buf[a]
if(buf[b] != 0) temp = buf[a]
exit(0)
printf("wrong")
printf("right")
指令数组
内存
数据区,存储操作数,这个是通过
seg000:0000026E lea edi, ds:0D48h[edi*4]
算出来的
seg000:00000F48 db 21h ; ! ; data start
seg000:00000F49 db 0
seg000:00000F4A db 0
seg000:00000F4B db 0
seg000:00000F4C db 0
seg000:00000F4D db 0
seg000:00000F4E db 0
seg000:00000F4F db 0
seg000:00000F50 db 81h
seg000:00000F51 db 0
seg000:00000F52 db 0
seg000:00000F53 db 0
seg000:00000F54 db 27h ; '
seg000:00000F55 db 0
seg000:00000F56 db 0
seg000:00000F57 db 0
seg000:00000F58 dd 2 dup(1), 24h, 2 dup(1), 23h, 2, 0
seg000:00000F78 db 22h ; "
seg000:00000F79 align 4
seg000:00000F7C db 3
seg000:00000F7D align 10h
seg000:00000F80 db 2
seg000:00000F81 align 4
seg000:00000F84 dd offset dword_0+21h
seg000:00000F88 dd 4, 8, 28h
seg000:00000F94 unk_F94 db 3 ; DATA XREF: seg000:00000ED4↑o
seg000:00000F95 align 4
seg000:00000F98 dd 4, 27h
seg000:00000FA0 unk_FA0 db 2 ; DATA XREF: seg000:00000EE0↑o
seg000:00000FA1 align 4
seg000:00000FA4 db 3
seg000:00000FA5 align 4
seg000:00000FA8 dd offset dword_0+28h
seg000:00000FAC db 3
seg000:00000FAD align 2
seg000:00000FAE word_FAE dw 0 ; DATA XREF: seg000:00000EEB↑o
seg000:00000FB0 dd 4, 27h, 2, 3, 28h, 3, 4, 27h, 2, 3, 27h, 2 dup(3), 23h
seg000:00000FB0 dd 4, 3, 24h, 3, 2, 27h, 2, 4, 24h, 0
seg000:00001010 db 2
seg000:00001011 align 4
seg000:00001014 dd offset dword_0+21h
seg000:00001018 dd 2 dup(1), 25h, 0
seg000:00001028 dd 1, 22h, 1, 0
seg000:00001038 dd offset dword_0+21h
seg000:0000103C db 2
seg000:0000103D align 10h
seg000:00001040 db 81h
seg000:00001041 align 4
seg000:00001044 dd offset dword_0+26h
seg000:00001048 dd 1, 2, 21h, 2, 9, 26h, 1, 2, 21h, 2, 9, 2Dh, 2, 1, 21h
seg000:00001048 dd 0
seg000:00001088 db 81h
seg000:00001089 align 4
seg000:0000108C db 22h ; "
seg000:0000108D align 10h
seg000:00001090 dd 1, 0
seg000:00001098 dd offset dword_0+21h
seg000:0000109C db 2
seg000:0000109D align 10h
seg000:000010A0 dd 9, 25h, 1, 2, 23h, 3, 0
seg000:000010BC db 23h ; #
seg000:000010BD align 10h
seg000:000010C0 dd 4, 1, 26h, 3, 4, 21h, 4, 7Eh, 2Dh, 4, 3, 21h, 3, 1
seg000:000010C0 dd 25h, 0
seg000:00001100 db 3
seg000:00001101 align 4
seg000:00001104 db 25h ; %
seg000:00001105 align 4
seg000:00001108 dd 1, 3, 26h, 2, 3, 21h, 4, 5Ah, 2Dh, 4, 2, 2Fh, 2 dup(0)
seg000:00001140 dd offset dword_0+30h
seg000:00001144 dd 2 dup(0)
seg000:0000114C db 38h ; 8
seg000:0000114D db 62h, 64h, 61h
dump
addr = 0x0F48
print "\nopt:"
while(1):
opt = Dword(addr)
a = Dword(addr + 4)
b = Dword(addr + 8)
print opt,",",a,",",b,",",
if(opt >= 0x2E):
break
addr += 12
翻译
妈耶,好不容易把指令翻译成了C语言,结果发现这段代码里面还嵌套了类似汇编的指令,还有循环,需要翻译
0 buf0 = 129 //buf0 = 129
1 buf1 ^= buf1 //buf1 = 0
2 (dword) data[buf1] = buf1 //data[0] = 0
3 buf2 = (dword) data[buf0] //buf2 = data[129]
4 buf3 = buf2 //buf3 = data[129]
5 buf4 = 8 //buf4 = 8
6 buf3 <<= buf4 //buf3 = data[129] << 8
7 buf2 ^= buf3 //buf2 = data[129] ^ (data[129] << 8)
8 buf3 <<= buf4 //buf3 = data[129] << 16
9 buf2 ^= buf3
10 buf3 <<= buf4
11 buf2 ^= buf3
//buf2 = data[129] ^ (data[129] << 8) ^ (data[129] << 16) ^ (data[129] << 24)
// = afterXor
12 buf3 ^= buf3 //buf3 = 0
13 buf4 = (dword) data[buf3] //buf4 = data[0]
14 (dword) data[buf3] = buf2 //data[0] = afterXor
15 buf2 ^= buf4 //buf2 = afterXor ^ data[0]
16 (dword) data[buf0] = buf2 //data[129] = afterXor ^ data[0]
17 buf1 = 1 //buf1 = 1
18 buf0 += buf1 //buf0 = 130
19 buf1 = buf0 //buf1 = 130
20 buf2 = 129 //buf2 = 129
21 buf1 -= buf2 //buf1 = 1
22 buf2 = 9 //buf2 = 9
23 buf1 -= buf2 //buf1 = -8
24 buf2 = 9 //buf2 = 9
25 if(buf1 != 0) temp = buf2 //经高人指点,这里是设置eip
//jmp 3
26 buf0 = 129 //buf0 = 129
27 buf1 = buf0 //buf1 = 129
28 buf2 = 9 //buf2 = 9
29 buf1 += buf2 //buf1 = 138
30 buf3 = (dword) data[buf0] //buf3 = data[129]
31 buf4 = (dword) data[buf1] //buf4 = data[138]
32 buf3 -= buf4 //buf3 = data[129] - data[138]
33 buf4 = 126 //buf4 = 126
34 if(buf3 != 0) temp = buf4 //jmp 42
35 buf3 = 1 //buf3 = 1
36 buf0 += buf3 //buf0 = data[129] - data[138] + 129
37 buf1 += buf3 //buf1 = 139
38 buf2 -= buf3 //buf2 = 8
39 buf4 = 90 //buf4 = 90
40 if(buf2 != 0) temp = buf4
41 printf("wrong")
42 printf("right")
再翻译
程序作了一个很奇怪的循环,并且异或了一大堆
这个程序要逆向实在太难了,考虑到本来这个数据也不大,就暴力枚举
script from yypE:
def dec(arr):
assert(len(arr)==9)
last = 0
for i in range(9):
var = 0
arr[i] ^= last
last = arr[i]
var |= arr[i] & 0xff
for j in range(1,4):
var |= (byte(arr[i],j) ^ byte(arr[i],j-1)) <<(8*j)
arr[i] = var
return arr
def enc(arr):
assert(len(arr)==9)
last = 0
for i in range(9):
var = 0
for j in range(4):
var ^= (arr[i]<<(8*j)) & 0xffffffff
arr[i] = var ^ last
last = var
return arr
获得flag:
def gen_flag():
ar = [1466127717, 106103809, 524896585, 1364657951, 1465860951, 1464032855, 1129775626, 1465779038, 257490944]
flag = b''
for each in dec(ar):
flag+=each.to_bytes(4,'little')
print(flag)
虚拟机+反汇编+循环+暴力搜索
难点
- 猜出来程序的入口点
- 猜出修改的temp变量原来是EIP
- 逆向带循环的程序
- 耐心