首页
社区
课程
招聘
[原创]第六题 寻回宝剑
2021-6-1 19:58 11098

[原创]第六题 寻回宝剑

2021-6-1 19:58
11098

这题开始做的时候顶着混淆硬做的 后来发现这个混淆类型还挺少的 尝试去一下混淆 锻炼一下自己的python能力

0x0 破障

图片描述

 

IDA 一进去 就可以看见 start函数的混淆 这种混淆很容易去掉

 

这里我使用的是 IDApython 去掉的这个混淆 原理是汇编的特征码

0x00 patch one

利用特征码定位混淆头部 在从头部按照一定偏移取出用来计算跳转位置的值

 

比如这里要先从 call $+5 执行后的 offset 取出 base

 

然后再从 xor rax,9BA38 取出 xored

 

跳转位置即用 base ^ xored 算出 再转成汇编字节码写入混淆头部

 

最后把其他未执行的混淆部分的指令 nop 掉

 

虽然 xor 的数值不同 造成特征码也不一样

 

不过没关系 写成模糊搜索就行了(后面才发现有个 idc.find_binary 可以直接用 不过写都写了2333

 

写成脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
def search(address,table):
    for i in range(len(table)):
        if table[i] != '?':
            if ida_bytes.get_byte(start+i) == table[i]:
                if i == len(table) - 1:
                    return 1
            else:
                return 0
 
def getshell(start):
    jmpst  = start + 8
    xored  = ida_bytes.get_dword(start+11)
    ret    = jmpst ^ xored
    asmret = ret - (start + 5)
    shell=[''] * 5 + (len(table) - 5) * [0x90]
    shell[0]=0xe9
    for i in range(4):
        shell[i+1] = (asmret & (0xff << i*8)) >> i * 8
    return shell
 
def fkret():
    start  = 0x140000000
    end    = 0x1400FA698
    count = 0
    while start <= end:
        if search(start,table) == 1:
            #print ('found at ' + str(hex(start))) 
            shell  = getshell(start)
            mypatch(start,shell)
            start += len(table) - 1
            count += 1
        start += 1
 
    print('fkret count='+str(count))
 
def mypatch(address,shell):
    for ch in shell:
        ida_bytes.patch_byte(address,ch)
        address += 1
 
table =[0x50,0x50,0x9c,0xe8,0x00,0x00,0x00,0x00,0x58,0x48,0x35,'?','?','?','?',0x48,0x89,0x44,0x24,0x10,0x9d,0x58,0xc3]
 
fkret()

fkret count=34213

0x01 patch two and three

保存以后再继续看 发现还是不好看 很多跳转

 

用 IDA trace 看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
push    rbx                        
jmp     loc_1400C446D              
pop     rbx                        
jmp     sub_14003F5A7              
push    rdx                        
push    rdx                        
pop     rdx                        
pop     rdx                        
push    rcx                        
jmp     loc_14001EE1F              
push    rdx                        
pop     rdx                        
push    rbx                        
pop     rbx                        
pop     rcx                        
jmp     sub_140071DE0              
sub     rsp, 28h                   
jmp     loc_1400B5E68              
push    rax                        
jmp     loc_1400904F3              
push    rdx                        
push    rdx                        
pop     rdx                        
pop     rdx                        
push    rax                        
jmp     loc_140081972              
push    rcx                        
pop     rcx                        
push    rbx                        
pop     rbx                        
pushfq                             
jmp     loc_14007FBCE              
push    rbx                        
pop     rbx                        
push    rax                        
push    rax                        
pushfq                             
call    $+5                        
pop     rax                        
xor     rax, 6665h                 
mov     [rsp+58h+var_48], rax      
popfq                              
pop     rax                        
jmp     sub_140079DBD              
push    rcx                        
pop     rcx                        
push    rdx                        
pop     rdx                        
pop     rax                        
jmp     sub_1400C9B65              
push    rbx                        
pop     rbx                        
add     rax, 36F74h                
jmp     loc_1400E169F              
push    rcx                        
push    rdx                        
pop     rdx                        
pop     rcx                        
mov     [rsp+arg_8], rax           
jmp     loc_14002BE91              
push    rcx                        
pop     rcx                        
popfq                              
jmp     loc_1400E2622              
push    rbx                        
pop     rbx                        
pop     rax                        
jmp     sub_1400F8E1D              
push    rcx                        
push    rbx                        
pop     rbx                        
pop     rcx                        
retn

这里就已经包含了两种混淆

 

一种是简单的 push reg && pop reg 以及这种混淆的嵌套 例如 push push pop pop

 

但这都还算好 问题就在于push pop 中间添加了 jmp 使得之前使用的汇编特征码的方法失效

 

另一种跟第一种差不多 不过嵌套了一层 另一个问题也是中间加了 jmp

 

手动去掉jmp 再去掉没用的push pop 可以看见这种混淆大概长这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
push    rax                        
push    rax                        
pushfq                             
push    rax                        
push    rax                        
pushfq                             
call    $+5                        
pop     rax                        
xor     rax, 6665h                 
mov     [rsp+10h], rax      
popfq                              
pop     rax                        
pop     rax                        
add     rax, 36F74h                
mov     [rsp+10h], rax           
popfq                              
pop     rax                        
retn

特征还蛮明显的噢

 

接下来就是写脚本

 

但是这个脚本咋写呢 手动的情况下是先去掉 jmp

 

但是如果直接在程序里面把 jmp nop掉肯定是不行的 影响了程序流程的正常执行

 

那就在判断的时候把 jmp 忽略掉咯 也就是暂且先做下一步 去掉push pop

 

若是要人来判断 会怎么做这一步呢

 

是不是先找到一句pop 然后返回去找push

 

再比较两者操作的寄存器是否相同

 

而要实现这一点 其实就相当于写模拟执行

 

要执行的话 肯定不止执行一句

 

而如果要执行多句 肯定需要知道当前指令的长度 然后才能够跳到下一句执行

 

那先写一个 getlen 用于获取当前指令长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def getlen(offset):
    p_op_len = {
    "pop" : 1,
    "push" : 1,
    "popfq" : 1,
    "pushfq" : 1,
    "nop" : 1,
    "retn" : 1,
}
    p_asm = idc.GetDisasm(offset)
    p_op  = p_asm.split(' ')[0]
    p_len = 1
    if not(p_op in p_op_len):
        while p_asm == idc.GetDisasm(offset + p_len):
            p_len += 1
    return p_len

这个 getlen 的原理呢 是一个指令如果已经被识别

 

GetDisasm 传的参如果不超过这一句的字节码 就一直会返回同一句汇编

 

用这个原理就需要特别掠过 1 字节的汇编指令

 

因为如果下一字节的汇编的指令与这一句的相同

 

就会误认为这一句指令的长度为 2

 

这种情况在这个程序里尤其多且不能够误判

 

比如两句push rax 误判的话栈都不平了

 

返回到上一步

 

之前说 '先找到一句pop 然后返回去找push'

 

这在模拟执行里面是很麻烦的

 

因为如果只根据反汇编 要去倒着找 似乎只能够把所有的步骤记录下来

 

那么把思路换一下

 

遇见 push 的时候 把操作的 reg 以及当前的 rip 储存起来

 

在下一次遇见 pop 的时候检查 reg 与上次 push 的是否相同

 

这样就可以完美解决如果上一句是 push reg 下一句 是 pop reg 的情况了

 

但是要是遇见嵌套的 push pop 一次是没法完美解决的

 

不过解决方法也很简单 多执行几次就行了

 

还要解决一下中间的 jmp

 

我开始想用 从反汇编中截取字符串 当作十六进制

 

比如 jmp loc_1400C446D 直接把 1400C446D 截取出来赋值给 rip 指针

 

但是后面发现有的 jmp 反汇编成 jmp xxx+xx 的形式 于是决定还是用硬编码来计算跳转地址

 

在运行过程中还发现有的与寻常的字节码不一样

 

例如 48 FF 25 19 68 F1 FF jmp cs:TerminateProcess

 

这种肯定不能真的计算到跳转地址去 还是直接掠过比较好

 

还有要注意正负的计算方式不一样

1
2
3
4
5
6
7
8
9
10
11
12
def calcjmp(offset):
    __asm = idc.GetDisasm(offset)
    if ida_bytes.get_byte(offset) == 0xE9:
        st = offset
        f = ida_bytes.get_dword(st + 1) & 0x80000000
        if f == 0x80000000:
            st = st - (0x100000000 - ida_bytes.get_dword(st + 1)) + 5
        else:
            st = st + ida_bytes.get_dword(st + 1) + 5
    else:
        st = offset + getlen(offset)
    return st

有了上面的铺垫 可以写去push pop 的混淆了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def fuckpush(offset):
    count = 0
    pat_count = 0
    debug = 0
    while count < 5:
        st = offset
        last = ''
        rip_push  = []
        reg_push = []
 
        while True:
            flag = 0
            __asm  = idc.GetDisasm(st)
            if debug == 1:
                print(__asm)
            op_len = getlen(st)
 
            if __asm == 'retn':
                count += 1
                break
 
            op  = __asm.split(' ')[0]
            reg = __asm.split(' ')[-1]
 
            if op == 'push':
                rip_push.append(st)
                reg_push.append(reg)
                last = 'push'
                flag = 1
 
            elif op == 'pop':
                if last == 'push':
                    if reg == reg_push[-1]:
                        if debug == 1:
                            print("patch " + str(hex(rip_push[-1])) + " + " + str(hex(st)))
                        ida_bytes.patch_byte(rip_push[-1],0x90)
                        ida_bytes.patch_byte(st,0x90)
                        pat_count += 1
                    flag = 0
 
            if op == 'jmp':
                st = calcjmp(st)
            else:
                if __asm != 'nop':
                    if flag == 0:
                        last = ''
                st += op_len
 
    print("fuck " + str(pat_count) + " pairs of 'push pop'")
    return pat_count

去掉了 push pop 之后 同样是比较特征之后 nop 相应代码并修改执行流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
def fuckret(offset,debug=0):
    table = ['push','push','pushfq','push','push','pushfq','call','pop','xor','mov','popfq','pop','pop','add','mov','popfq','pop','retn']
    st = offset
    fkcnt = 0
    fkpus = 0
    fkpus += fuckpush(st)
    while True:
        __asm = idc.GetDisasm(st)
        if debug == 1:
            if __asm != 'nop':
                print("out : " + str(hex(st)) ,end='\t')
                print(__asm)
 
        op_len = getlen(st)
        op  = __asm.split(' ')[0]
 
        if op == 'push':
            if debug == 1:
                print('')
            asmrip  = []
            lastjmp = 0
            op_cnt  = 0
            st_in   = st
            while True:
                __asm = idc.GetDisasm(st)
                if debug == 1:
                    if __asm != 'nop':
                        print("inn : " + str(hex(st)) ,end='\t')
                        print(__asm)
 
                op_len = getlen(st)
                op = __asm.split(' ')[0]
 
                if op == 'jmp':
                    lastjmp = st
                    st = calcjmp(st)
                elif op == 'nop':
                    st += 1
                elif op == table[op_cnt]:
                    asmrip.append(st)
                    st += op_len
                    op_cnt += 1
                else:
                    st = st_in + 1
                    break
 
                if op_cnt == 18:
                    if ida_bytes.get_byte(lastjmp) != 0xE9:
                        st = st_in + 1
                        break
                    if debug == 1:
                        print("rip : ",end='')
                        for sb in asmrip:
                            print(str(hex(sb)) + ',', end='')
                        print('')
 
                    calladdr = asmrip[6]                    #getshell
                    xored    = ida_bytes.get_dword(asmrip[8] + 2)
                    added    = ida_bytes.get_dword(asmrip[13] + 2)
                    if added > 0x7fffffff:
                        added = -(0x100000000 - added)
                    jmp_addr = ( (calladdr + 5) ^ xored ) + added
                    if lastjmp > jmp_addr:
                        asmret = 0xFFFFFFFF - (lastjmp + 5 - jmp_addr) +1
                    else:
                        asmret = jmp_addr - (lastjmp + 5)
                    shell = [''] * 5
                    shell[0] = 0xe9
                    for j in range(4):
                        shell[j+1] = (asmret & (0xff << j*8)) >> j * 8
 
                    for killd in asmrip:                    #clear rubbish
                        kil_op_len = getlen(killd)
                        for kil_i in range(kil_op_len):
                            ida_bytes.patch_byte( killd + kil_i, 0x90)
                            kil_i += 1
 
                    if debug == 1:
                        print('from ' + str(hex(asmrip[0])) + ' to ' + str(hex(asmrip[-1])) + ' be patched')
                        print('from ' + str(hex(lastjmp)) + ' jmp to ' + str(hex(jmp_addr)))
                    mypatch(lastjmp,shell)#patch jmp
                    fkcnt += 1
                    st = lastjmp
 
                    if debug == 1:
                        print('\n')
                    fkpus += fuckpush(st)
                    break
 
        elif op == 'jmp':
            st = calcjmp(st)
        elif op == 'retn':
            print("fuck " + str(fkcnt) + " pairs of 'pop ret'")
            return fkcnt + fkpus
        else:
            st += op_len

不过我写的逻辑是直到不能够处理的 retn 就停下来

 

所以只能够先 trace 一遍有混淆的

 

再写个脚本把 retn 下一行的代码的地址提取出来(大部分都可以这样解决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import os, time, sys, re
file = open("./trace1.txt",encoding="utf8")
key = "ret"
flag = 0
sb = []
for line in file.readlines():
 
    if flag == 1:
        ssb = int(line.split('|')[1].strip(),16)
        if ssb < 0x200000000:
            sb.append(ssb)
        flag = 0
        continue
    if key in line:
        flag = 1
file.close()
 
for i in sb:
    print(str(hex(i)),end=',')

后面一边 trace 一边 patch 不过我直接把我 patch 完的所有有效地址写上吧 可以省掉大家很多复现的时间

1
2
3
4
5
6
7
8
fucklist=[0x14004085a,0x1400224c8,0x1400424a2,0x1400dfcb1,0x14001206c,0x140019e2e,0x14001f509,0x14007a881,0x140097094,0x140026507,0x1400c07b3,0x1400a17bf,0x1400eed90,0x140041d1f,0x140049ec5,0x140068125,0x14008874d,0x14003d3a8,0x1400ba55e,0x1400b4dc9,0x14009480a,0x1400d1602,0x1400db842,0x14008a584,0x14007cfa7,0x140035884,0x14000f9e9,0x1400e63a4,0x1400c3492,0x1400143c9,0x1400e1d72,0x14009e7f0,0x140032c3c,0x140033e50,0x14009881b,0x1400308b6,0x1400beea3,0x14004460b,0x1400bcb75,0x1400b0cdc,0x14005edb0,0x14007de2e,0x140086a9f,0x1400f575b,0x140017f67,0x14008e5cd,0x140030dea,0x1400adcb7,0x1400857c4,0x1400025b9,0x1400b6283,0x1400ac98b,0x1400d22ff,0x14004e3ca,0x140099671,0x140099677,0x14000391a,0x14007c539,0x1400bb3c7,0x14008f046,0x1400a978f,0x14009b70f,0x1400a6b74,0x140045f2e,0x140037db2,0x140021128,0x1400e549d,0x140088782,0x140069be7,0x14004c42b,0x140044fae,0x1400533d0,0x14006bf6a,0x1400a0c6c,0x14003a608,0x14001cae6,0x1400f63e6,0x1400affb6,0x14000d8f7,0x14003f111,0x140046bcf,0x140066b81,0x14006734f,0x140063405,0x14005c245,0x1400a8f62,0x140050474,0x14006b372,0x1400e9fea,0x1400f5667,0x1400ba5aa,0x140021277,0x1400f8634,0x1400bcce5,0x1400386f9,0x1400f5741,0x140040fed,0x1400ae5a0,0x1400de1b6,0x1400127b9,0x1400afa4c,0x14009cbfe,0x14004d06f,0x1400f74bb,0x1400b0bad,0x1400aa0b4,0x1400e86dc,0x14003d6b8,0x1400407ed,0x1400ee996,0x14006b83d,0x1400932f0,0x14001c061,0x140020e62,0x14007c505,0x14004c19b,0x1400403f6,0x14003d086,0x1400609dd,0x1400645e4,0x14002ade3,0x1400201b3,0x1400585f8,0x1400344a2,0x14003746d,0x140093ae9,0x1400f8f00,0x14003cb4b,0x1400a0472,0x14004cc27,0x1400a720f,0x140062b19,0x1400d7e9d,0x140035b53,0x1400489eb,0x1400c93d1,0x140049b13,0x1400b6994,0x1400dc2a0,0x1400b1d93,0x14007a048,0x1400bbdb4,0x140093534,0x1400a939a,0x140065701,0x1400ac86b,0x14003c7f8,0x1400b2b4d,0x1400e5d05,0x1400c9ee6,0x1400961bf,0x1400d1abe,0x1400e6ac8,0x1400c8f1f,0x14005e050,0x140095e85,0x1400610a1,0x14003a0b5,0x1400cda74,0x14009367b,0x1400c26a0,0x1400b3149,0x140024323,0x14000234c,0x1400175a1,0x14001a8f0,0x1400a1493,0x140052dc1,0x1400cfa4f,0x1400c82e5,0x14008e488,0x140026895,0x1400d667c,0x14002cd55,0x1400f5c45,0x14008bf75,0x140010075,0x1400190b3,0x1400de7d0,0x14008d5d4,0x1400e4a0c,0x1400a7382,0x140037876,0x1400d5016,0x1400c7b84,0x14003ad82,0x140065331,0x140013029,0x1400b4f3a,0x14008c9ee,0x1400c376e,0x1400f95db,0x14003eb8e,0x140070774,0x140051198,0x1400bd38a,0x14008c893,0x140041e14,0x140092f4a,0x1400e487b,0x1400f75f6,0x140021d1b,0x140013251,0x14005047c,0x140028abd,0x1400e5392,0x1400a8349,0x14007619b,0x14004cfaf,0x140051b04,0x140020bc7,0x1400122e2,0x140079ad8,0x1400c5aa9,0x14008fdb8,0x1400b6b57,0x1400ef67c,0x14008239c,0x14008f521,0x140084df2,0x1400d203c,0x1400108a1,0x1400e399d,0x140021f1c,0x14001d98f,0x1400d9e3c,0x1400a86dd,0x1400ce809,0x140032394,0x140093660,0x14001f168,0x14009aabc,0x1400ed298,0x1400dc6f5,0x140002691,0x1400b603b,0x14009c76a,0x140053a4f,0x1400411dc,0x1400411e2,0x1400cf6b9,0x140049b81,0x140053fcb,0x1400fa16d,0x14001d49c,0x14002d10f,0x14009644f,0x140068922,0x1400f734a,0x1400195f6,0x1400b932b,0x1400a7f82,0x140020c11,0x1400d1807,0x14006b86f,0x1400a0e4f,0x140033127,0x1400db36d,0x14005cf3b,0x14005d401,0x1400d70e7,0x14006b0e0,0x14009b72b,0x14004f9a3,0x1400cb0a9,0x1400d9db0,0x1400677e0,0x1400113c0,0x1400e0c75,0x140042cfe,0x14000bcd7,0x14009a73b,0x1400b0a29,0x1400a25e7,0x1400de3af,0x140097af0,0x14000b885,0x1400e2a2a,0x1400fa18e,0x1400017a2,0x1400f7e0d,0x1400e08ef,0x14008b954,0x140039307,0x140080b6f,0x140017839,0x140062a08,0x140019442,0x1400b5921,0x140011462,0x1400f9d12,0x1400d91a0,0x140012fa9,0x140067ef0,0x1400b7c3d,0x1400752dd,0x14002715b,0x140010b61,0x1400e9d43,0x1400f0464,0x1400ded5f,0x1400843dd,0x1400843e1,0x14008020d,0x140028484,0x1400f8380,0x140053e38,0x140036180,0x140080d39,0x1400a6c18,0x1400b6324,0x1400de837,0x1400a7352,0x14007cd16,0x1400f0f20,0x14007cfdd,0x14009002f,0x140080a00,0x1400f1551,0x1400be82f,0x1400a9650,0x1400f84de,0x140017f67,0x14008e5cd,0x140030dea,0x1400adcb7,0x1400857c4,0x1400025b9,0x1400b6283,0x1400ac98b,0x1400d22ff,0x14004e3ca,0x140099671,0x140099677,0x14000391a,0x14007c539,0x1400bb3c7,0x14008f046,0x1400a978f,0x14009b70f,0x1400a6b74,0x140045f2e,0x140037db2,0x140021128,0x1400e549d,0x140088782,0x140069be7,0x1400021e4,0x14005f397,0x140064bf6,0x140025c2d,0x140017f67,0x14008e5cd,0x140030dea,0x1400adcb7,0x1400857c4,0x1400025b9,0x1400b6283,0x1400ac98b,0x1400d22ff,0x14004e3ca,0x140099671,0x140099677,0x14000391a,0x14007c539,0x1400bb3c7,0x14008f046,0x1400a978f,0x14009b70f,0x1400a6b74,0x140045f2e,0x140037db2,0x140021128,0x1400e549d,0x140088782,0x140069be7,0x1400ce142,0x140076982,0x1400453d7,0x140078961,0x1400a0c6c,0x14003a608,0x14001cae6,0x1400f63e6,0x1400affb6,0x14000d8f7,0x14003f111,0x140046bcf,0x140066b81,0x14006734f,0x140063405,0x14005c245,0x1400a8f62,0x140050474,0x14006b372,0x1400e9fea,0x1400f5667,0x1400ba5aa,0x140021277,0x1400f8634,0x1400bcce5,0x1400386f9,0x1400f5741,0x140040fed,0x1400ae5a0,0x1400de1b6,0x1400127b9,0x1400afa4c,0x14009cbfe,0x14004d06f,0x1400f74bb,0x1400b0bad,0x1400aa0b4,0x1400e86dc,0x14003d6b8,0x1400407ed,0x1400ee996,0x14006b83d,0x1400932f0,0x14001c061,0x140020e62,0x14007c505,0x14004c19b,0x1400403f6,0x14003d086,0x1400609dd,0x1400645e4,0x14002ade3,0x1400201b3,0x1400585f8,0x1400344a2,0x14003746d,0x140093ae9,0x1400f8f00,0x14003cb4b,0x1400a0472,0x14004cc27,0x1400a720f,0x140062b19,0x1400d7e9d,0x140035b53,0x1400489eb,0x1400c93d1,0x140049b13,0x1400b6994,0x1400dc2a0,0x1400b1d93,0x14007a048,0x1400bbdb4,0x140093534,0x1400a939a,0x140065701,0x1400ac86b,0x14003c7f8,0x1400b2b4d,0x1400e5d05,0x1400c9ee6,0x1400961bf,0x1400d1abe,0x1400e6ac8,0x1400c8f1f,0x14005e050,0x140095e85,0x1400610a1,0x14003a0b5,0x1400cda74,0x14009367b,0x1400c26a0,0x1400b3149,0x140024323,0x14000234c,0x1400175a1,0x14001a8f0,0x1400a1493,0x140052dc1,0x1400cfa4f,0x1400c82e5,0x14008e488,0x140026895,0x1400d667c,0x14002cd55,0x1400f5c45,0x14008bf75,0x140010075,0x1400190b3,0x1400de7d0,0x14008d5d4,0x1400e4a0c,0x1400a7382,0x140037876,0x1400d5016,0x1400c7b84,0x14003ad82,0x140065331,0x140013029,0x1400b4f3a,0x14008c9ee,0x1400c376e,0x1400f95db,0x14003eb8e,0x140070774,0x140051198,0x1400bd38a,0x14008c893,0x140041e14,0x140092f4a,0x1400e487b,0x1400f75f6,0x140021d1b,0x140013251,0x14005047c,0x140028abd,0x1400e5392,0x1400a8349,0x14007619b,0x14004cfaf,0x140051b04,0x140020bc7,0x1400122e2,0x140079ad8,0x1400c5aa9,0x14008fdb8,0x1400b6b57,0x1400ef67c,0x14008239c,0x14008f521,0x140084df2,0x1400d203c,0x1400108a1,0x1400e399d,0x140021f1c,0x14001d98f,0x1400d9e3c,0x1400a86dd,0x1400ce809,0x140032394,0x140093660,0x14001f168,0x14009aabc,0x1400ed298,0x1400dc6f5,0x140002691,0x1400b603b,0x14009c76a,0x140053a4f,0x1400411dc,0x1400411e2,0x1400cf6b9,0x140049b81,0x140053fcb,0x1400fa16d,0x14001d49c,0x14002d10f,0x14009644f,0x140068922,0x1400f734a,0x1400195f6,0x1400b932b,0x1400a7f82,0x140020c11,0x1400d1807,0x14006b86f,0x1400a0e4f,0x140033127,0x1400db36d,0x14005cf3b,0x14005d401,0x1400d70e7,0x14006b0e0,0x14009b72b,0x14004f9a3,0x1400cb0a9,0x1400d9db0,0x1400677e0,0x1400113c0,0x1400e0c75,0x140042cfe,0x14000bcd7,0x14009a73b,0x1400b0a29,0x1400a25e7,0x1400de3af,0x140097af0,0x14000b885,0x1400e2a2a,0x1400fa18e,0x1400017a2,0x1400f7e0d,0x1400e08ef,0x14008b954,0x140039307,0x140080b6f,0x140017839,0x140062a08,0x140019442,0x1400b5921,0x140011462,0x1400f9d12,0x1400d91a0,0x140012fa9,0x140067ef0,0x1400b7c3d,0x1400752dd,0x14002715b,0x140010b61,0x1400e9d43,0x1400f0464,0x1400ded5f,0x1400843dd,0x1400843e1,0x14008020d,0x140028484,0x1400f8380,0x140053e38,0x140036180,0x140080d39,0x1400a6c18,0x1400b6324,0x1400de837,0x1400a7352,0x14007cd16,0x1400f0f20,0x14007cfdd,0x14009002f,0x140080a00,0x1400f1551,0x14006fb9d,0x140013ffa,0x140064e88,0x140017f67,0x14008e5cd,0x140030dea,0x1400adcb7,0x1400857c4,0x1400025b9,0x1400b6283,0x1400ac98b,0x1400d22ff,0x14004e3ca,0x140099671,0x140099677,0x14000391a,0x14007c539,0x1400bb3c7,0x14008f046,0x1400a978f,0x14009b70f,0x1400a6b74,0x140045f2e,0x140037db2,0x140021128,0x1400e549d,0x140088782,0x140069be7,0x140064e90,0x140034e9b,0x140074ce9,0x1400ee88d,0x140017f67,0x14008e5cd,0x140030dea,0x1400adcb7,0x1400857c4,0x1400025b9,0x1400b6283,0x1400ac98b,0x1400d22ff,0x14004e3ca,0x140099671,0x140099677,0x14000391a,0x14007c539,0x1400bb3c7,0x14008f046,0x1400a978f,0x14009b70f,0x1400a6b74,0x140045f2e,0x140037db2,0x140021128,0x1400e549d,0x140088782,0x140069be7,0x1400d8db6,0x14006cd36,0x1400c0765,0x140061681,0x1400a0c6c,0x14003a608,0x14001cae6,0x1400f63e6,0x1400affb6,0x14000d8f7,0x14003f111,0x140046bcf,0x140066b81,0x14006734f,0x140063405,0x14005c245,0x1400a8f62,0x140050474,0x14006b372,0x1400e9fea,0x1400f5667,0x1400ba5aa,0x140021277,0x1400f8634,0x1400bcce5,0x1400386f9,0x1400f5741,0x140040fed,0x1400ae5a0,0x1400de1b6,0x1400127b9,0x1400afa4c,0x14009cbfe,0x14004d06f,0x1400f74bb,0x1400b0bad,0x1400aa0b4,0x1400e86dc,0x14003d6b8,0x1400407ed,0x1400ee996,0x14006b83d,0x1400932f0,0x14001c061,0x140020e62,0x14007c505,0x14004c19b,0x1400403f6,0x14003d086,0x1400609dd,0x1400645e4,0x14002ade3,0x1400201b3,0x1400585f8,0x1400344a2,0x14003746d,0x140093ae9,0x1400f8f00,0x14003cb4b,0x1400a0472,0x14004cc27,0x1400a720f,0x140062b19,0x1400d7e9d,0x140035b53,0x1400489eb,0x1400c93d1,0x140049b13,0x1400b6994,0x1400dc2a0,0x1400b1d93,0x14007a048,0x1400bbdb4,0x140093534,0x1400a939a,0x140065701,0x1400ac86b,0x14003c7f8,0x1400b2b4d,0x1400e5d05,0x1400c9ee6,0x1400961bf,0x1400d1abe,0x1400e6ac8,0x1400c8f1f,0x14005e050,0x140095e85,0x1400610a1,0x14003a0b5,0x1400cda74,0x14009367b,0x1400c26a0,0x1400b3149,0x140024323,0x14000234c,0x1400175a1,0x14001a8f0,0x1400a1493,0x140052dc1,0x1400cfa4f,0x1400c82e5,0x14008e488,0x140026895,0x1400d667c,0x14002cd55,0x1400f5c45,0x14008bf75,0x140010075,0x1400190b3,0x1400de7d0,0x14008d5d4,0x1400e4a0c,0x1400a7382,0x140037876,0x1400d5016,0x1400c7b84,0x14003ad82,0x140065331,0x140013029,0x1400b4f3a,0x14008c9ee,0x1400c376e,0x1400f95db,0x14003eb8e,0x140070774,0x140051198,0x1400bd38a,0x14008c893,0x140041e14,0x140092f4a,0x1400e487b,0x1400f75f6,0x140021d1b,0x140013251,0x14005047c,0x140028abd,0x1400e5392,0x1400a8349,0x14007619b,0x14004cfaf,0x140051b04,0x140020bc7,0x1400122e2,0x140079ad8,0x1400c5aa9,0x14008fdb8,0x1400b6b57,0x1400ef67c,0x14008239c,0x14008f521,0x140084df2,0x1400d203c,0x1400108a1,0x1400e399d,0x140021f1c,0x14001d98f,0x1400d9e3c,0x1400a86dd,0x1400ce809,0x140032394,0x140093660,0x14001f168,0x14009aabc,0x1400ed298,0x1400dc6f5,0x140002691,0x1400b603b,0x14009c76a,0x140053a4f,0x1400411dc,0x1400411e2,0x1400cf6b9,0x140049b81,0x140053fcb,0x1400fa16d,0x14001d49c,0x14002d10f,0x14009644f,0x140068922,0x1400f734a,0x1400195f6,0x1400b932b,0x1400a7f82,0x140020c11,0x1400d1807,0x14006b86f,0x1400a0e4f,0x140033127,0x1400db36d,0x14005cf3b,0x14005d401,0x1400d70e7,0x14006b0e0,0x14009b72b,0x14004f9a3,0x1400cb0a9,0x1400d9db0,0x1400677e0,0x1400113c0,0x1400e0c75,0x140042cfe,0x14000bcd7,0x14009a73b,0x1400b0a29,0x1400a25e7,0x1400de3af,0x140097af0,0x14000b885,0x1400e2a2a,0x1400fa18e,0x1400017a2,0x1400f7e0d,0x1400e08ef,0x14008b954,0x140039307,0x140080b6f,0x140017839,0x140062a08,0x140019442,0x1400b5921,0x140011462,0x1400f9d12,0x1400d91a0,0x140012fa9,0x140067ef0,0x1400b7c3d,0x1400752dd,0x14002715b,0x140010b61,0x1400e9d43,0x1400f0464,0x1400ded5f,0x1400843dd,0x1400843e1,0x14008020d,0x140028484,0x1400f8380,0x140053e38,0x140036180,0x140080d39,0x1400a6c18,0x1400b6324,0x1400de837,0x1400a7352,0x14007cd16,0x1400f0f20,0x14007cfdd,0x14009002f,0x140080a00,0x1400f1551,0x1400255b8,0x1400e31b1,0x1400875e0,0x1400ba9cc,0x1400aca2c,0x1400b8ef7,0x14008a498,0x14004849e,0x1400ec496,0x14007afe0,0x1400920af,0x1400c9bcb,0x1400e18bb,0x1400b873b,0x14000f17c,0x140026de4,0x1400ed51b,0x140002a2b,0x1400866d4,0x140070872,0x14005b83e,0x14009341f,0x1400b74ac,0x14005bf73,0x1400d8fa2,0x140058517,0x14004545f,0x1400b80cb,0x1400b1e14,0x1400cb869,0x1400b78c0,0x1400f5b05,0x140017e14,0x1400a3f95,0x14007816c,0x140031b63,0x14004bd45,0x1400f6131,0x1400b3d6f,0x140055cca,0x140033675,0x14006781a,0x1400528e0,0x14005890e,0x1400b7575,0x14006d905,0x1400add65,0x1400f6918,0x140029440,0x1400201b3,0x1400585f8,0x1400344a2,0x14003746d,0x140093ae9,0x1400f8f00,0x14003cb4b,0x1400a0472,0x14004cc27,0x1400a720f,0x140062b19,0x1400d7e9d,0x140035b53,0x1400489eb,0x1400c93d1,0x140049b13,0x1400b6994,0x1400dc2a0,0x1400b1d93,0x14007a048,0x1400bbdb4,0x140093534,0x1400a939a,0x140065701,0x1400ac86b,0x14003c7f8,0x1400b2b4d,0x1400e5d05,0x1400618cc,0x1400d4c95,0x14008b527,0x140024dd7,0x14002893c,0x1400cee23,0x1400c8251,0x1400bcd83,0x1400d591a,0x140084140,0x140027a64,0x14008c361,0x1400DFC26,0x140084AF9,0x14000E2D5,0x14000EEBD,0x1400889B6,0x14006390E,0x14007C4CD,0x140012781,0x140048357,0x1400596FF,0x14008807F,0x140014acc,0x140022c16,0x1400e6a73,0x140014D26,0x140091363, 0x140014acc,0x14006E7A8,0x14004785B,0x1400E2890,0x14008334E,0x140061f8b,0x1400620f3, 0x1400d75d7,0x1400d50cf,0x140082b78,0x1400d1579,0x140024af6,0x14006cf3b,0x1400d0f8e, 0x14006689C,0x140057B79,0x1400D58AC,0x140001a06,0x1400b5d46,0x1400e1e42,0x1400B9910, 0x14002A213,0x1400BC169,0x14003AB45,0x14006D099,0x14006b00b,0x1400c86f1,0x1400f9bfa, 0x140021245,0x1400EC7AE,0x1400A5B1A,0x1400C9E5E,0x140039D11]
path = []
for i in fucklist:
#    print(hex(i))
    AutoMark(i,AU_CODE)
#    fuckret(i)
    if fuckret(i) > 0:
        path.append(i)

0x02 patch etc

去完以上混淆以后

 

再尝试 trace

 

图片描述

 

可以利用以下正则表达式去掉 trace 文本中的很多无用信息

1
2
3
^(.*)jmp(.*)\r\n
^(.*)nop(.*)\r\n
^(.*)00007FFF(.*)\r\n

然后可以发现还剩下一些 pop retn 没有去掉

 

没有去掉的原因呢 是因为仍然有变种的 pop retn

 

这种变种的 pop retn 中插了有意义的代码 如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
push    rax                        
push    rax                        
pushfq                             
push    rax                        
push    rax                        
pushfq                             
call    $+5                        
pop     rax                        
xor     rax, 6665h                 
mov     [rsp+10h], rax      
popfq                              
pop     rax                        
pop     rax                        
add     rax, 36F74h                
mov     [rsp+10h], rax           
popfq                              
pop     rax
mov        eax, 1###有用的代码
retn

这种混淆要识别有用的代码 而且各个有用的代码都不相同 有的甚至是嵌套 pop ret 给识别带来很大的困难

 

考虑到此时已经可以大概看的了汇编了 于是就不准备再继续写 patch 了

0x1 还原

直接调试被 patch 以后的程序 F9运行到挂起等待输入 点击暂停 随便输入以后会断下来

 

按 alt+F9 回到用户代码段

1
000000014008C365    call r10//scanf

在system函数下断点 从这里开始 trace

0x10 检查长度

把结果中的 nop jmp 系统函数地址的代码 全部替换为空

 

尝试搜索一下cmp 发现一个可疑的地方

 

图片描述

 

图片描述

 

再调试确认一下输入 84 长度的假码 rax == 54 很明显这里的逻辑就是

1
2
3
if(strlen(input) != 0x54)
    print(' >>> 阁下的数学成绩堪忧,请回吧。')
    system("pause")

0x11 输入范围

继续往下 trace

 

trace完用前面的那个找ret的下一行的脚本 再用前面的去混淆 保存 再trace就很干净了

 

很容易可以看见一个循环 找到几句关键代码

1
2
3
4
5
6
140027B39   cmp eax,30
1400CBFAD   cmp eax,39
1400A27A9   cmp eax,41
1400A07D9   cmp eax,5A
1400BE069   cmp qword ptr ss:[rsp+B0],54
140069753   jge patch3.14006976C

这里很明显就是比较输入范围是 0-9 A-Z

0x12 转换输入

再从循环尾往下找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
1400731D7    mov byte ptr ss:[rsp+7],cl
1400938D7    cmp eax,30
14001A372    cmp eax,39
140069CAB    sub rax,30
 
14000224D    cmp eax,41
1400B2DC9    cmp eax,5A
14004B966    sub rax,41
140094D9C    add rax,A
 
14007F965    mov qword ptr ss:[rsp+A8],rax
140054381    cmp qword ptr ss:[rsp+A8],2A
 
1400BA991    imul rax,rax,2A

观察了一下分支是从这个比较错开的

1
2
1400906DB    cmp rax,qword ptr ss:[rsp+rcx*8+EC0]
1400A9B93    jg patch3.1400A9BAC

查看了一下寄存器这里比较的是1AF 与25B

 

再查询了一下上下文

 

我的输入是 ABCDEFABCDEF....

 

1AF 是由 0xA * 0x2a + 0xB算来的 25B是由0xE * 0x2a + 0xF

 

同时这里的循环计次变量为3

 

可以推算出 把输入从 str 变成了 hex 之后

1
2
3
if( i != 0)
    if( input_hex[i]*0x2a+input_hex[i+1] < input_hex[i-2]*0x2a+input_hex[i-1] )
        GG

当前这一位前一位 * 0x2a + 后一位

 

也就是把 hex 的两位看成一位来运算

 

此时感觉有点不对 输入10位数字加上26位字母只有36位 而他比较42位 感觉还有几位输入

 

输入了一些不是上面范围的字符 再跑了一下 发现了剩下的几位

1
2
3
4
5
6
140045713   cmp eax,2B +
140071B51   cmp eax,2D -
1400F5DA9   cmp eax,2A *
140014C52   cmp eax,2F /
140081C7A   cmp eax,25 %
140003A93   cmp eax,3D =

转换之后是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1400F5A62 | 83F8 2B                  | cmp eax,2B
140003A25 | 48:C74424 08 24000000    | mov qword ptr ss:[rsp+8],24
 
140096D4F | 83F8 2D                  | cmp eax,2D
1400528A1 | 48:C74424 08 25000000    | mov qword ptr ss:[rsp+8],25
 
14001E900 | 83F8 2A                  | cmp eax,2A
14005337E | 48:C74424 08 26000000    | mov qword ptr ss:[rsp+8],26
 
1400F3D8E | 83F8 2F                  | cmp eax,2F
14000C5FA | 48:C74424 08 27000000    | mov qword ptr ss:[rsp+8],27
 
140064EDF | 83F8 25                  | cmp eax,25
1400AEF1C | 48:C74424 08 28000000    | mov qword ptr ss:[rsp+8],28
 
1400C9DE1 | 83F8 3D                  | cmp eax,3D
14007B859 | 48:C74424 08 29000000    | mov qword ptr ss:[rsp+8],29

很好现在已经把输入范围和输入转换搞定了 继续往下看

0x13 重复检查

再往下发现还是走不下去

 

在走不下去的附近有如下逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
14007D9D5    mov qword ptr ss:[rsp+A0],0
140002310    cmp qword ptr ss:[rsp+A0],2A
140001F98    mov rax,qword ptr ss:[rsp+A0]
 
14002D5AC    mov rax,qword ptr ss:[rsp+rax*8+EC0]
140073E00    mov ecx,2A
14009EA4F    idiv rcx
14006EC35    mov qword ptr ss:[rsp+98],rdx            //[rsp+98]=change[i]%0x2A
140060863    mov rdx,qword ptr ss:[rsp+A0]
140063300    mov rdx,qword ptr ss:[rsp+rdx*8+EC0]
140017083    mov rax,rdx
1400BCF6C    idiv rcx
1400BF3EF    mov qword ptr ss:[rsp+90],rax            //[rsp+90]=change[i]/0x2A
 
1400BF3EF    mov rax,qword ptr ss:[rsp+98]
14004B8F8    test byte ptr ss:[rsp+rax+E90],1
14005224C    mov rax,qword ptr ss:[rsp+90]
140015F89    test byte ptr ss:[rsp+rax+E60],1
 
140027ACE    mov rax,qword ptr ss:[rsp+98]
1400E4C50    mov byte ptr ss:[rsp+rax+E90],1
1400AC622    mov rax,qword ptr ss:[rsp+90]
1400B5248    mov byte ptr ss:[rsp+rax+E60],1
140037CD0    mov rax,qword ptr ss:[rsp+A0]
140026ABB    add rax,1
1400258E6    mov qword ptr ss:[rsp+A0],rax

这里得取余和除法其实是把 hex形式 再重新提取出来了

 

然后以其作为数组下标,去一个表中判断

 

如果没有被填过 那就填入并继续循环

 

如果已经被填过 那就GG

 

用代码来说的话就是

1
2
3
4
5
6
7
8
table1[0x2a]={}
table2[0x2a]={}
for i in range(0,len(input_hex),2):
    if table1[input_hex[i]] == 0 and table2[input_hex[i+1]] == 0:
        table1[input_hex[i]] = 1
        table2[input_hex[i+1]] = 1
    else
        GG

用人话来理解就是 奇数位 和 偶数位 的输入序列 每一个输入只允许出现一次

 

结合此两位大于前两位的规则

 

可以知道奇数位已经是确定为

 

0123456....+-*/%=

0x14 落子检查

输入满足当前条件的输入再继续往下 trace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
1400C86F5   mov qword ptr ss:[rsp+88],0            
1400D320E   cmp qword ptr ss:[rsp+88],2A                //循环1
140056B2F   jge patch3.140056B48                        //[rsp+88] = i
 
1400CBE10   mov rax,qword ptr ss:[rsp+88]          
140052E9D   add rax,1                              
140078F7F   mov qword ptr ss:[rsp+80],rax               //[rsp+80] = j = i + 1
1400286DB   cmp qword ptr ss:[rsp+80],2A                //循环2
14000D91A   jge patch3.14000D933                   
                                                        //change == rsp+EC0
1400F755C   mov rax,qword ptr ss:[rsp+88]          
140098656   mov rax,qword ptr ss:[rsp+rax*8+EC0]       
140001584   cqo                                    
1400A4ADC   mov ecx,2A                             
14001F9E4   idiv rcx                               
14009D9EA   mov r8,qword ptr ss:[rsp+80]           
1400EDA1E   mov r8,qword ptr ss:[rsp+r8*8+EC0]     
14000EA19   mov rax,r8                             
1400A04C3   mov qword ptr ss:[rsp+38],rdx               //[rsp+38] = change[i] % 0x2a
140037898   cqo                                    
14008A550   idiv rcx                               
1400399F2   mov r8,qword ptr ss:[rsp+38]           
1400D4106   sub r8,rdx                                  //[rsp+78] = [rsp+38] - change[j] % 0x2a
1400901F7   mov qword ptr ss:[rsp+78],r8           
14009DAAD   mov rdx,qword ptr ss:[rsp+88]          
14000E4E3   mov rdx,qword ptr ss:[rsp+rdx*8+EC0]       
1400EE409   mov rax,rdx                            
1400C5EE9   cqo                                    
140020832   idiv rcx                               
14008C074   mov r8,qword ptr ss:[rsp+80]           
14006079F   mov r8,qword ptr ss:[rsp+r8*8+EC0]     
140013395   mov qword ptr ss:[rsp+30],rax               //[rsp+30] = change[j] / 0x2a
1400C5CE1   mov rax,r8                             
14002FFF8   cqo                                    
14007539E   idiv rcx                               
14006BF8A   mov rcx,qword ptr ss:[rsp+30]          
1400DB4A6   sub rcx,rax                            
1400E127D   mov qword ptr ss:[rsp+70],rcx               //[rsp+70] = [rsp+30] - change[i] / 0x2a
140073B88   cmp qword ptr ss:[rsp+78],0
14006437E    jge patch3.140064397                        //若满足条件跳转 下面这一段不执行
 
1400BFF7E   xor eax,eax                     
1400EACB4   mov ecx,eax                     
140080A4A   mov rdx,rcx                     
1400A7967   sub rdx,qword ptr ss:[rsp+78]   
1400517AC   mov qword ptr ss:[rsp+78],rdx                //[rsp+78] = -[rsp+78]
14000B3C6   sub rcx,qword ptr ss:[rsp+70]   
14008DA3A   mov qword ptr ss:[rsp+70],rcx                //[rsp+70] = -[rsp+70]
 
1400B368C   mov rax,qword ptr ss:[rsp+70]   
140079E70   add rax,29                                  
1400DE855   mov qword ptr ss:[rsp+70],rax                //[rsp+70] += 0x29
14007C0C8   imul rax,qword ptr ss:[rsp+70],2A
1400DC9B8   lea rcx,qword ptr ss:[rsp+C0]                //[rsp+C0] == table
140038FE8   add rcx,rax                     
140067202   mov rax,qword ptr ss:[rsp+78]   
14008B8FD   test byte ptr ds:[rcx+rax],1                 //table[[rsp+70] * 0x2a + [rsp+78]] == 1  -> gg
140063B11   je patch3.140063B2A

转成伪代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
ih = input_hex
for i in range(0,42*2,2):
    for j in range(i+2,42*2,2):
        v70 = ih[j] - ih[i]
        v78 = ih[j+1] - ih[i+1]
        if v78 < 0 :
            v78 = -v78
            v70 = -v70
        index = (v70 + 41) * 42 + v78
        if table[index] != 0:
            table[index] = 0
        else:
            GG

结合题目描述 这应该是模拟了一个棋盘 而 input_hex 每两位是一个 point(x,y)

 

棋盘大小是 4242 也就是题目所提示的 36\49

 

而落子方式并非简单的 x,y 代入 而是以任意两点为基础

1
2
Y = (y' - y < 0) ?  flag = 1, y - y' : y' - y
X = (flag == 1 ? x - x' : x' - x) + 41

按此方式落子 若不重复 且全部子落完即可满足条件

 

考虑到用爆破来解这个题复杂度一定很高 而且也有可能有多解

 

猜测后面还有限制条件没找到

0x15 多解检查

再在外层循环判断尾的时候直接跳过 trace 赫然就发现

1
2
3
4
5
6
7
140039540    lea rcx,qword ptr ss:[rsp+1010]
1400CE591    lea rdx,qword ptr ds:[140004521]
//140004521    "02152S3X4Z5Q6C7T819/ADB%C*DL"
14004CACF    mov r8d,1C                     
14004FED9    call qword ptr ds:[<&strncmp>] 
 
140021803    cmp rcx,0

把比较结果再改掉 发现直接提示成功了

 

说明到这里程序的所有逻辑就已经完全 dump 完了

 

接下来就是如何解的问题了

0x2 解局

利用以上已知条件直接模拟爆破即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include<stdio.h>
char table[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-*/%=";
char flag[100] = "02152S3X4Z5Q6C7T819/ADB%C*DL";
int finx(char tofind)
{
    if (tofind == 0)
        return -1;
    for (int i = 0; table[i]; ++i)
        if (table[i] == tofind)
            return i;
}
 
int toc(int ind)
{
    return table[ind];
}
 
int check(char index, char fill)
{
    for (int i = 0; i < index; ++i)
        if (flag[i * 2 + 1] == fill)
            return 0;//false if again
 
    char ctable[5000] = {};
 
    for (int i = 0; i < index * 2; i += 2)
    {
        int x = flag[i],
            y = flag[i + 1];
        for (int j = i + 2; j < index * 2; j += 2)
        {
            int x_ = flag[j],
                y_ = flag[j + 1];
 
            int tmp = y_ - y,
                tmp2 = x_ - x;
 
            if (tmp < 0)
            {
                tmp = -tmp;
                tmp2 = -tmp2;
            }
            int indx = (tmp2 + 41) * 42 + tmp;
 
            if (ctable[indx] == 0)
                ctable[indx] = 1;
            else
                return 0;
        }
    }//check down
 
    return 1;
}
 
void slove()
{
    int index;
    for (int i = 0; i < 42; ++i)
        if (!flag[i * 2 + 1])
        {
            index = i * 2 + 1;
            break;
        }
 
    for (int i = 0; i < 42 * 2; ++i)
    {
        if (flag[i] != 0)
            flag[i] = finx(flag[i]);
        else
            flag[i] = -1;
    }
 
    for (int j = index / 2; j < 42; ++j)
    {
        int fflag = 0;
 
        int st = flag[index];
        if (st != -1)//pass the wrong way
            st += 1;
        else
            st = 0;
        for (int i = st; i < 42; ++i)
        {
            if (check(index / 2, i))
            {
                fflag = 1;
                flag[index] = i;
                index += 2;
                flag[index] = -1;
                break;
            }
        }
        if (!fflag)//in this index all is cant check,so ret after
        {
            j -= 2;
            index -= 2;
        }
    }
 
    for (int i = 0; i < 42 * 2; ++i)
    {
        flag[i] = toc(flag[i]);
    }
}
 
int main()
{
 
    for (int i = 0; i < 42; ++i)
        flag[i * 2] = toc(i);
    slove();
    printf("%s\n", flag);
}

大概20分钟可以爆破出来

02152S3X4Z5Q6C7T819/ADB%C*DLEIFUG3HRIHJ6K7L0MBNKOJPPQ=RNS+TEUOVWWGXYYMZ9+4-8*F/-%V=A


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2021-6-1 21:30 被|_|sher编辑 ,原因:
收藏
点赞8
打赏
分享
最新回复 (2)
雪    币: 3072
活跃值: (20)
能力值: ( LV1,RANK:40 )
在线值:
发帖
回帖
粉丝
0x99er 2021-6-2 10:51
2
0
分析的详细!
雪    币: 8283
活跃值: (4811)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
v0id_ 2021-6-3 12:42
3
0
usher tql
游客
登录 | 注册 方可回帖
返回