初音未来の消失

国赛_2018 write up

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

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)

虚拟机+反汇编+循环+暴力搜索

难点

  1. 猜出来程序的入口点
  2. 猜出修改的temp变量原来是EIP
  3. 逆向带循环的程序
  4. 耐心
退出移动版