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='')
posted @ 2022-09-04 13:46  wgf4242  阅读(319)  评论(0编辑  收藏  举报