moectf2022 re WriteUp
chicken soup
花指令入门
.text:00401088 57 push edi
.text:00401089 74 03 jz short near ptr loc_40108D+1 ; jz跳到8d+1
.text:00401089
.text:0040108B 75 01 jnz short near ptr loc_40108D+1 ; jnz跳到8d+1
.text:0040108B
.text:0040108D
.text:0040108D loc_40108D: ; CODE XREF: .text:00401089↑j
.text:0040108D ; .text:0040108B↑j
.text:0040108D E9 C7 45 F8 00 jmp near ptr 1385659h ; 所以jmp识别的不对, nop掉E9, 先U再Ctrl+N
jn/jnz都跳,说明肯定跳转 8d+1的位置即 C7 45 F8 这里。E9命令会略过,不会执行。JMP识别的不对报错。按u再Ctrl+N nop掉E9, 再F5
识别后就比较简单了,先是a1[i] += a1[i + 1];,然后高低位互换。逆一下。
enc = [0xCD, 0x4D, 0x8C, 0x7D, 0xAD, 0x1E, 0xBE, 0x4A, 0x8A, 0x7D, 0xBC, 0x7C, 0xFC, 0x2E, 0x2A, 0x79, 0x9D, 0x6A, 0x1A, 0xCC, 0x3D, 0x4A, 0xF8, 0x3C, 0x79, 0x69, 0x39, 0xD9, 0xDD, 0x9D, 0xA9, 0x69, 0x4C, 0x8C, 0xDD, 0x59, 0xE9, 0xD7]
for i, c in enumerate(enc):
enc[i] = (c << 4 | c >> 4 ) &0xff
for i in range(len(enc) - 1, -1, -1):
c = enc[i]
enc[i - 1] -= enc[i] & 0xff
for c in enc:
print(chr(c), end='')
# moectf{p4tch_pr0gr4m_t0_d3c0mpi1e_it!}
find key
main启动之前,调用了sub_401800() -> sub_401790()-> qword_402E80 -> 401550h 这个顺序最后调用 401550h。
复制了 'yunzh1junTCL,trackYYDS'到 main中v6处。
sub_401800();
v6 = strlen("yunzh1junTCL,trackYYDS");
...
for ( i = 0; i < lenInput; ++i )
Str[i] ^= aYunzh1juntclTr[i % v6];
for ( j1 = 0; j1 < lenInput; ++j1 )
Str[j1] += rand() % 10;
if ( sub_4015A2((__int64)Str, (__int64)byte_403020) )
puts("\nRight! TTTTTQQQQQLLLLL!!!");
按逻辑逆向回去即可。中间rand()部分需要调试打印出来每轮的rand值。或者自己编译个c。输出29轮rand()。
rlst = [41, 18467, 6334, 26500, 19169, 15724, 11478, 29358, 26962, 24464, 5705, 28145, 23281, 16827, 9961, 491, 2995, 11942, 4827, 5436, 32391, 14604, 3902, 153, 292, 12382, 17421, 18716, 19718]
rlst = [x % 10 for x in rlst]
enc2 = list(bytes.fromhex('15210F19255B19395F3A3B307407433F095A340C743F1E2D272112161F'))
enc1 = [(x - rlst[i]) for i, x in enumerate(enc2)]
key = list(b'yunzh1junTCL,trackYYDS')
for i, c in enumerate(enc1):
r = chr(c ^ key[i % len(key)])
print(r, end='')
# moectf{D3bug_t0_g3t_7he_Key!}
fake code
题目说明了有SEH。异常结构。看了一下汇编是简单的异或处理。
方式一。在异或时使用密文异或,比较下断下自动出明文。
.text:00007FF602D91217 movsxd rcx, cs:n19
.text:00007FF602D9121E lea rdx, byte_7FF602D95010 ; key
.text:00007FF602D91225 movzx ecx, byte ptr [rdx+rcx] ; keyN19
.text:00007FF602D91229 movzx eax, [rsp+rax+0D8h+var_88]
.text:00007FF602D9122E xor eax, ecx ; 直接这里下断,粘贴上加密后的字符。
.text:00007FF602D91230 movsxd rcx, [rsp+0D8h+i]
.text:00007FF602D91235 mov [rsp+rcx+0D8h+var_88], al
.text:00007FF602D91239 jmp loc_7FF602D911A3
结尾比较处下断,内存中查看异或的结果。
if ( !strcmp(enc, v7) )
puts("\nQwQ, please try again.");
else
puts("\nTTTTTTTTTTQQQQQQQQQQQQQLLLLLLLLL!!!!");
return 0;
# moectf{Re4d_4ssemb1y_t0_g3t_the_m4gic_key_0f_Tr4ck}
方式二。分析SEH流程。。
.text:00007FF602D911B8 ; 19: v5 = (127 * v5 + 102) % 255;
.text:00007FF602D911B8
.text:00007FF602D911B8 loc_7FF602D911B8: ; DATA XREF: .rdata:00007FF602D93880↓o
.text:00007FF602D911B8 ; __try { // __except at loc_7FF602D911E9
.text:00007FF602D911B8 imul eax, [rsp+36], 127
.text:00007FF602D911BD add eax, 102 ; eax = 127 * v5 + 102
.text:00007FF602D911C0 cdq
.text:00007FF602D911C1 mov ecx, 0FFh
.text:00007FF602D911C6 idiv ecx ; eax / 0xff = eax 商 edx余数
.text:00007FF602D911C8 mov eax, edx ; 余数给eax
.text:00007FF602D911CA mov [rsp+0D8h+j], eax ; j = 余
.text:00007FF602D911CE mov eax, [rsp+0D8h+j] ; eax = 余
.text:00007FF602D911D2 sar eax, 7 ; eax = eax >> 7
.text:00007FF602D911D5 mov [rsp+0D8h+k], eax ; k = eax
.text:00007FF602D911D9 mov eax, 1 ; eax = 1
.text:00007FF602D911DE cdq
.text:00007FF602D911DF idiv [rsp+0D8h+k] ; k为0时异常。向下跳到except
.text:00007FF602D911E3 mov [rsp+0D8h+k], eax
.text:00007FF602D911E7 jmp short loc_7FF602D91212
.text:00007FF602D911E7 ; } // starts at 7FF602D911B8
简单分析
eax,edx = divmod(127 * v5 + 102, 255)
eax = edx
k = eax >> 7
eax = 1
if k== 0 :
goto _except
k = eax = 1
n19 = (97 * n19 + 101) % 233
n19 ^= 0x29
goto loc_7FF602D91212
_except:
j = (127 * j + 102) % 255;
loc_7FF602D91212:
v7[i] ^= byte_7FF602D95010[n19];
修复程序
int __cdecl sub_7FF602D91100(int argc, const char **argv, const char **envp)
{
int i; // [rsp+20h] [rbp-B8h]
int j; // [rsp+24h] [rbp-B4h]
__int64 len; // [rsp+30h] [rbp-A8h]
char v7[112]; // [rsp+50h] [rbp-88h] BYREF
j = 0;
puts("Can you read my assembly in exception?");
puts("Give me your flag:");
sub_7FF602D91290("%s", v7);
len = -1i64;
do
++len;
while ( v7[len] );
if ( len == 51 )
{
for ( i = 0; i < 51; ++i )
{
j = (127 * j + 102) % 255;
if ( !(j >> 7) )
{
n19 = (97 * n19 + 101) % 233;
n19 ^= 0x29u;
}
v7[i] ^= byte_7FF602D95010[n19];
}
if ( !strcmp(enc, v7) )
puts("\nQwQ, please try again.");
else
puts("\nTTTTTTTTTTQQQQQQQQQQQQQLLLLLLLLL!!!!");
return 0;
}
else
{
puts("\nQwQ, please try again.");
return 0;
}
}
汇编修复部分:
.text:00007FF602D911B8 loc_7FF602D911B8: ; DATA XREF: .rdata:00007FF602D93880↓o
.text:00007FF602D911B8 ; __try { // __except at loc_7FF602D911E9
.text:00007FF602D911B8 imul eax, [rsp+36], 127
.text:00007FF602D911BD add eax, 102
.text:00007FF602D911C0 cdq
.text:00007FF602D911C1 mov ecx, 0FFh
.text:00007FF602D911C6 idiv ecx ; eax 商 edx余数
.text:00007FF602D911C8 mov eax, edx ; 余数给eax
.text:00007FF602D911CA mov [rsp+0D8h+j], eax ; j = 余
.text:00007FF602D911CE mov eax, [rsp+0D8h+j] ; eax = 余
.text:00007FF602D911D2 sar eax, 7 ; eax >> 7
.text:00007FF602D911D5 mov [rsp+0D8h+k], eax ; k = eax >> 7
.text:00007FF602D911D9 test eax, eax
.text:00007FF602D911DB jnz short loc_7FF602D9120C
.text:00007FF602D911DD nop
.text:00007FF602D911DE nop
...
.text:00007FF602D911E8 ; } // starts at 7FF602D911B8
Art
核心逻辑
for ( i = 0; i <= 27; ++i )
v4[i] = Str1[i];
for ( i = 1; i <= 27; ++i )
Str1[i - 1] ^= (Str1[i - 1] % 17 + Str1[i]) ^ 0x19;
if ( !strcmp(Str1, &Str2) && (unsigned int)sub_401550(v4) )
puts("\nGood job!!! You know UPX and hash!!!");
from natsort import natsorted
from z3 import *
s = [BitVec('s1_%d' % i, 8) for i in range(28)] # 有时得用int值好使
enc = bytes.fromhex('02180FF8190427D8EB0035484D2A456B592E4301185C09090909B57D')
solver = Solver()
for i in range(1,28):
s[i - 1] ^= (s[i - 1] % 17 + s[i]) ^ 0x19
for i in range(28):
solver.add(s[i] == enc[i])
print(solver.check())
res = solver.model()
art
lst = natsorted([(k, res[k]) for k in res], lambda x: str(x[0]))
for k, v in lst:
print(chr(v.as_long()), end='')