MINIRE

有upx壳,并且把upx改为gcc了

两种解法 一种是hook运算操作,尝试还原算法,我比赛时就是用的这种,但是这题校验非常难找,导致比赛时一直没找到,另一种是单字节爆破

方法一

脱壳,f5发现没法反编译

但是ghidra是可以的,它没有栈限制

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
case 'X':
  local_20 = 0;
  while (local_1c = local_1c + 1, *(char *)(param_1 + local_1c) != 'x') {
    (&stack0xffffffffffc24328)[local_20] = *(undefined *)(param_1 + local_1c);
    local_20 = local_20 + 1;
  }
  (&stack0xffffffffffc24328)[local_20] = 0;
  if (1 < local_20) {
    if (in_stack_ffffffffffc24328 != 'V') {
      for (local_24 = 1;
          ((local_24 < local_20 && ('/' < (char)(&stack0xffffffffffc24328)[local_24])) &&
          ((char)(&stack0xffffffffffc24328)[local_24] < ':')); local_24 = local_24 + 1) {
      }
    }
    iVar7 = (int)in_stack_ffffffffffc24328;
    if (iVar7 == 0x20) {
      bVar1 = (&DAT_005175a0)[DAT_00768090];
      bVar5 = FUN_00405c10(&stack0xffffffffffc24329);
      (&DAT_005175a0)[DAT_00768090] = bVar1 ^ bVar5;
      iVar6 = DAT_00768094;
    }
    else if (((0x1f < iVar7) && (iVar7 < 0x6b)) && (0x40 < iVar7)) {
      switch(iVar7) {
      case 0x41:
        cVar2 = (&DAT_005175a0)[DAT_00768090];
        cVar4 = FUN_00405c10(&stack0xffffffffffc24329);
        (&DAT_005175a0)[DAT_00768090] = cVar2 * cVar4;
        iVar6 = DAT_00768094;
        break;
      case 0x4a:
        iVar7 = FUN_00405c10(&stack0xffffffffffc24329);
        iVar6 = DAT_00768094;
        if (iVar7 != 0) {
          cVar2 = (&DAT_005175a0)[DAT_00768090];
          cVar4 = FUN_00405c10(&stack0xffffffffffc24329);
          (&DAT_005175a0)[DAT_00768090] = cVar2 + cVar4;
          iVar6 = DAT_00768094;
        }
        break;
      case 0x51:
        cVar2 = (&DAT_005175a0)[DAT_00768090];
        cVar4 = FUN_00405c10(&stack0xffffffffffc24329);
        (&DAT_005175a0)[DAT_00768090] = cVar2 - cVar4;
        iVar6 = DAT_00768094;
        break;
      case 0x54:
        bVar1 = (&DAT_005175a0)[DAT_00768090];
        bVar5 = FUN_00405c10(&stack0xffffffffffc24329);
        (&DAT_005175a0)[DAT_00768090] = bVar1 | bVar5;
        iVar6 = DAT_00768094;
        break;
      case 0x55:
        uVar3 = FUN_00405c10(&stack0xffffffffffc24329);
        (&DAT_005175a0)[DAT_00768090] = uVar3;
        iVar6 = DAT_00768094;
        break;
      case 0x5f:
        cVar2 = (&DAT_005175a0)[DAT_00768090];
        cVar4 = FUN_00405c10(&stack0xffffffffffc24329);
        (&DAT_005175a0)[DAT_00768090] = cVar2 + cVar4;
        iVar6 = DAT_00768094;
        break;
      case 0x61:
        iVar7 = FUN_00405c10(&stack0xffffffffffc24329);
        iVar6 = DAT_00768094;
        if (iVar7 != 0) {
          bVar1 = (&DAT_005175a0)[DAT_00768090];
          bVar5 = FUN_00405c10(&stack0xffffffffffc24329);
          (&DAT_005175a0)[DAT_00768090] = bVar1 / bVar5;
          iVar6 = DAT_00768094;
        }
        break;
      case 0x6a:
        bVar1 = (&DAT_005175a0)[DAT_00768090];
        bVar5 = FUN_00405c10(&stack0xffffffffffc24329);
        (&DAT_005175a0)[DAT_00768090] = bVar1 & bVar5;
        iVar6 = DAT_00768094;

对应的找到各个运算的位置下断点,很容易就能得到加密逻辑

xor: 0x66,0x4
add: 0xC,0x62,0xC
xor: 0x6E,0xB
xor: 0x65,0xC
sub: 0x69,0x2
sub: 0x67,0x1
xor: 0x66,0x6
add: 0xA,0x6C,0xA
xor: 0x76,0xC
add: 0x5,0x7A,0x5
add: 0x4,0x61,0x4
add: 0xE,0x65,0xE
sub: 0x67,0xA
sub: 0x5D,0x3
add: 0xD,0x5A,0xD
add: 0x7,0x67,0x7
sub: 0x6E,0x9
xor: 0x65,0xE
sub: 0x7B,0x7
sub: 0x74,0xF
xor: 0x30,0xE
xor: 0x31,0x2
add: 0x0,0x33,0x0
xor: 0x33,0x2
add: 0x9,0x31,0x9
add: 0x3,0x3A,0x3
sub: 0x3D,0x2
add: 0xD,0x3B,0xD
xor: 0x48,0x1
add: 0x8,0x32,0x8
add: 0xC,0x3A,0xC
xor: 0x46,0xF
add: 0x5,0x49,0x5
xor: 0x4E,0x3
add: 0x8,0x4D,0x8
add: 0x8,0x33,0x8
add: 0x2,0x3B,0x2
xor: 0x3D,0x8
sub: 0x35,0xC
add: 0xB,0x29,0xB
sub: 0x34,0x3
xor: 0x31,0x9
sub: 0x38,0x2
add: 0x8,0x36,0x8
sub: 0x34,0x0
sub: 0x34,0x2
add: 0xB,0x35,0xB
sub: 0x36,0x2
xor: 0x34,0x7
sub: 0x33,0x1
sub: 0x32,0x5
add: 0x1,0x37,0x1
sub: 0x38,0xD
add: 0xC,0x2B,0xC
sub: 0x38,0x2
sub: 0x36,0xE
sub: 0x28,0x9
xor: 0x1F,0xE
add: 0x1,0x11,0x1
add: 0xA,0x12,0xA
sub: 0x1C,0x7
sub: 0x15,0x1
add: 0x9,0x14,0x9
sub: 0x39,0x0
sub: 0x39,0xB
xor: 0x2E,0x4
add: 0x9,0x2A,0x9
xor: 0x61,0xE
add: 0x5,0x6F,0x5
sub: 0x74,0xC
sub: 0x68,0x4
sub: 0x64,0x4
add: 0xF,0x60,0xF
add: 0xE,0x6F,0xE
sub: 0x7D,0x4
xor: 0x79,0x5
sub: 0x7C,0xC
xor: 0x62,0xB
add: 0xD,0x69,0xD
sub: 0x76,0xB
xor: 0x6B,0x4
add: 0xA,0x6F,0xA
sub: 0x79,0x8
add: 0xA,0x63,0xA
add: 0xF,0x6D,0xF
add: 0x2,0x7C,0x2
sub: 0x7E,0x6
sub: 0x78,0x9
sub: 0x6F,0x9
add: 0x3,0x66,0x3
add: 0x5,0x69,0x5
sub: 0x6E,0xF
add: 0x2,0x5F,0x2
sub: 0x64,0xE
sub: 0x56,0xD
xor: 0x65,0x7
sub: 0x62,0xF
sub: 0x53,0x1
xor: 0x52,0x3
sub: 0x51,0x3
add: 0xB,0x4E,0xB
add: 0xA,0x59,0xA
add: 0xA,0x63,0xA
add: 0x8,0x66,0x8
sub: 0x6E,0x6
sub: 0x68,0x7
xor: 0x61,0x4
sub: 0x65,0x1
xor: 0x64,0x3
add: 0x5,0x30,0x5
add: 0x2,0x35,0x2
add: 0xA,0x37,0xA
xor: 0x41,0x0
sub: 0x31,0x7
add: 0x0,0x2A,0x0
add: 0x8,0x2A,0x8
add: 0x1,0x32,0x1
add: 0x1,0x33,0x1
xor: 0x34,0xA
sub: 0x3E,0xE
xor: 0x30,0xF
sub: 0x3F,0x7
xor: 0x38,0x8
xor: 0x32,0x4
sub: 0x36,0x9
add: 0xF,0x2D,0xF
add: 0xC,0x33,0xC
xor: 0x3F,0x2
xor: 0x3D,0x4
sub: 0x39,0x7
add: 0x1,0x32,0x1
add: 0x0,0x34,0x0
add: 0x9,0x34,0x9
xor: 0x3D,0x2
add: 0xE,0x3F,0xE
xor: 0x4D,0xB
xor: 0x46,0x1
add: 0x2,0x47,0x2
add: 0x9,0x49,0x9
sub: 0x52,0x9
add: 0x6,0x35,0x6
xor: 0x36,0xA
sub: 0x3C,0x4
sub: 0x38,0xD
xor: 0x2B,0x8
sub: 0x23,0xE
add: 0xE,0x15,0xE
xor: 0x23,0xE
add: 0x1,0x37,0x1
xor: 0x38,0x4
sub: 0x3C,0x9
add: 0x9,0x33,0x9
sub: 0x3C,0x5
add: 0xD,0x37,0xD
add: 0x1,0x44,0x1
xor: 0x45,0xA
xor: 0x38,0x9
add: 0xE,0x39,0xE
add: 0xC,0x47,0xC
xor: 0x53,0x0
sub: 0x53,0x0
sub: 0x53,0xF
xor: 0x44,0xB
sub: 0x4F,0xB
add: 0x8,0x44,0x8
add: 0xB,0x61,0xB
add: 0x6,0x6C,0x6
add: 0x1,0x72,0x1
xor: 0x73,0xC
sub: 0x7F,0x6
sub: 0x79,0xE
sub: 0x62,0xB
xor: 0x57,0xD
add: 0x5,0x5A,0x5
xor: 0x5F,0x2
sub: 0x5D,0x2
add: 0xD,0x63,0xD
xor: 0x70,0x6
add: 0xF,0x76,0xF
xor: 0x85,0x0
sub: 0x85,0x3
sub: 0x82,0xC
sub: 0x76,0xF
xor: 0x67,0xB
add: 0x9,0x64,0x9
add: 0xA,0x6D,0xA
add: 0xA,0x77,0xA
xor: 0x81,0xA
sub: 0x65,0xD
xor: 0x66,0x7
sub: 0x61,0x0
sub: 0x7D,0xB
add: 0xE,0x72,0xE
sub: 0x80,0x8
add: 0x4,0x78,0x4
add: 0x3,0x7C,0x3
add: 0xD,0x7F,0xD
xor: 0x8C,0x3
xor: 0x8F,0xA

这里打印的时候可以格式化一下,便于后续写脚本,因为没想到能直接写z3()

参考0xcafebabe师傅的题解给出的脚本格式,会非常方便搞成z3,但是这里需要看出来eax - 46 就是index

1
2
3
4
5
import ida_dbg
index = ida_dbg.get_reg_value('RAX') - 0x46
# 获取 R8D 寄存器的值
EDX_value = ida_dbg.get_reg_val("EDX")
print(f"x[{value}]^= 0x{EDX_value:X}")

接着就是找密文或者校验逻辑了,但是比赛卡这地方卡了一下午ww

后来将多个点全hook,并根据已知正确的前五个字符'flag{'的加密结果,可以发现其读的方式

image-20241111201150608

image-20241111201137045

猜测应该是存于某一个连续内存的,hook方式如下

image-20241111201359214

1
2
3
import ida_dbg
EAX_value = ida_dbg.get_reg_val("EAX")
print(f"case 69: 0x{EAX_value:X}")
1
2
3
4
5
import ida_dbg
EAX_value = ida_dbg.get_reg_val("EAX")
print(f"case 69: 0x{EAX_value:X}")
if EAX_value == 0X99:
    fuck

通过上述脚本可断于特定位置,跟以下发现了以下内存块存储了enc

image-20241111153105992

然后即可用z3解了

脚本可参考https://blog.hxzzz.asia/,属实是懒得写z3了

方法二

比赛的时候原本是有想用的,但是看波动范围比较大就没用,下来试了下发现没问题

插桩点分别是handler与数据清理出

image-20241111200055097

hook.js

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
var number = 0
function main()
{
    var base =  Module.findBaseAddress("minire")
 
    if(base){
        // MemoryAccessMonitor.enable([{ base: base.add(0x1175Ec), size: 6 }], {
        //     onAccess: function(details) {
        //         number += 1
        //     }
        // });
        Interceptor.attach(base.add(0x2B57), {
     
                onEnter: function(args) {
                    number += 1
                }
    
            });
        Interceptor.attach(base.add(0x60F0), {
            onEnter: function(args) {
                send(number)
                Thread.sleep(0.001)
            }
        });
    }
}
setImmediate(main);

brute.py

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
import subprocess
import frida
import sys
import time
 
visible_chars = [
    ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    ':', ';', '<', '=', '>', '?', '@',
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    '[', '\\', ']', '^', '_', '`',
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    '{', '|', '}', '~'
]
 
# 定义全局变量
number = 0
flaglen = 32
filename = "./minire"  # 在 Linux 中,确保此文件是可执行文件
flag = bytearray(b'flag{' + b'!'*32 + b'}'# 初始 flag 值
jscode = open("hook.js", "rb").read().decode()
new_number = 0
result = 0
 
def test(F):
    def on_message(message, data):
        global result
        if message['type'] == 'send':
            result = message['payload']
        else:
            print(message)
 
    # 写入输入数据
    process = subprocess.Popen([filename,"root"], stdin=subprocess.PIPE,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE,
                               universal_newlines=True)
    time.sleep(0.1)
    session = frida.attach("minire")
    script = session.create_script(jscode)
    script.on('message', on_message)
    script.load()
 
    process.stdin.write(F.decode())
     
    # 读取输出并终止进程
    output, error = process.communicate()
    process.terminate()
    session.detach()
 
    return result
max_number = 0
right_chr = 0
flag = bytearray(b'flag{' + b'!' * 32 + b'}')
for i in range(flaglen):
    for j in visible_chars:
        flag[5+i] = ord(j)
        number = test(flag)
        if number >= max_number:
            max_number = number
            right_chr = ord(j)
    flag[5+i] = right_chr
    max_number = 0
    right_chr = 0      
    print(flag)
    print(number)

最新回复:
lishua 2025-01-06 16:14:50
这个题目可以给个下载链接么?  想学习一下,网上搜了搜都没找到。。。 多谢
z2zccc 2025-01-06 16:45:33
lishua 这个题目可以给个下载链接么? 想学习一下,网上搜了搜都没找到。。。 多谢
链接:https://pan.quark.cn/s/80c269695999
提取码:stPW 不好意思师傅 这题目可能是pcb的 那几天打的比赛比较多可能搞混了 您看看这个
lishua 2025-01-06 16:50:27
有了,多谢分享。
lishua 2025-01-07 15:50:12
果然比较变态,我找到了hash对比的地方,想着应该不可能就解个hash,还要脱壳。。算了,嫌麻烦,好久没学习脱壳的工具了 继续学习一下楼主别的帖子