当前位置:网站首页>2022 Top Net Cup Quals Reverse Partial writeup

2022 Top Net Cup Quals Reverse Partial writeup

2022-08-10 02:51:00 1mmorta1

Game

nativeThe layer actually only has two functions for encryption and decryption,So nothing reversed,直接用frida hook

  1. 由于有root检测和frida检测,换个端口启动 ./frida-server-15.1.8-android-arm64 -l 0.0.0.0:27049
  2. Then you can directly call the encryption and decryption functions:
/* docs: https://frida.re/docs/javascript-api/ adb root adb shell cd /data/local ./frida-server py3 adb forward tcp:27049 tcp:27049 frida-ps -H 127.0.0.1:27049 frida -H 127.0.0.1:27049 -f com.silence.scoreboard -l try.js --no-pause */

var HttpRequest = Java.use('com.silence.scoreboard.http.HttpRequest');
var OOOO = Java.use('com.silence.utils.OooOoo0');

OOOO.decrypt("SWeH8ou9yuL8GLThYhY1QlDiWX880+uNZusmIll/Q4Q=");
// "&Od987$2sPa?>l<k^j"
OOOO.decrypt("IbaoQT/3eTXIjHDJ2L5TQE==");
//"admin"

Mainly in reversejava层的逻辑,All data are in sum47.93.244.181服务器进行交互,因此只要在com.silence.scoreboard.http.HttpRequest It is enough to understand the logic of a few interactions.

  1. 通过scoreboard http://47.93.244.181/re/ScoreBoard.php Find a high scoreadmin "IbaoQT/3eTXIjHDJ2L5TQE==”(a.k.a. admin)

  2. Obtained by adding friendsadmin的account $.post(‘AddFriend.php’, {code:‘123125’})

  3. 获得flag username = ‘admin’; account = “&Od987$2sPa?>l<k^j”; $.post(‘GetFlag.php’, {code:‘123125’, account,username})

在这里插入图片描述

easyre

  1. It can be known by reading the main program,The program writes a subroutinere3并ptrace它,It will be based on interruptionsRIP的内容解密、Re-encrypt a piece of code.

  2. 使用straceGet all system calls,(All writes to subroutines passptrace实现),解析PTRACE_POKETEXT并patch程序(Decrypted part only)

    lines = open(r'stracedump.txt').read().splitlines()
    lines = [line for line in lines if line.startswith('ptrace(PTRACE_POKETEXT, ')]
    delta = 0x555555554000
    lines = [(int(line[31:][:14], 16) - delta, int(line[47:-5].strip(), 16)) for line in lines]
    lines = lines[:0x27]
    [patch_qword(addr, value) for addr, value in lines]
    

    setjmp和longjmpPart of the code should just write a loop comparison process

  3. Hardware breakpoints on and off the two arrays to be compared,Notice that the subroutine starts by swapping the last two arrays compared.

  4. 用z3Solve the corresponding problem(队内4老师的脚本!I draw it by myself55):

    linescan = bytes.fromhex('0605010302010100000000000000000000000000000000000008010101010101010100000000000000000000000000000000070301030104010100000000000000000000000000000000000801010102010101010000000000000000000000000000000007010401030201030000000000000000000000000000000000000000000000000000000000000000000000000000000000000604040401010100000000000000000000000000000000000008010202010201020100000000000000000000000000000000080101010103040301000000000000000000000000000000000A01010101010101010101000000000000000000000000000007030103010401010000000000000000000000000000000000010200000000000000000000000000000000000000000000000601010401010400000000000000000000000000000000000007080101010102010000000000000000000000000000000000080101010101010104000000000000000000000000000000000A0202010201010101010100000000000000000000000000000502050101030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060C0201010101000000000000000000000000000000000000090201010101010101010000000000000000000000000000000704070201010101000000000000000000000000000000000009010102010101010101000000000000000000000000000000020C02000000000000000000000000000000000000000000000401010101000000000000000000000000000000000000000004040201010000000000000000000000000000000000000000')
    assert 625 == len(linescan)
    linescan = [[linescan[i*25+j] for j in range(25)] for i in range(25)]
    
    cowscan = bytes.fromhex('050505030103000000000000000000000000000000000000000A0101010101010101010100000000000000000000000000000701010501030101000000000000000000000000000000000005010204050100000000000000000000000000000000000000070502010101010100000000000000000000000000000000000501010101050000000000000000000000000000000000000005010206010300000000000000000000000000000000000000070202010101010100000000000000000000000000000000000602050103010100000000000000000000000000000000000009010101010101010301000000000000000000000000000000070201010101010100000000000000000000000000000000000402050301000000000000000000000000000000000000000005030501010100000000000000000000000000000000000000080101010101010101000000000000000000000000000000000601010103050500000000000000000000000000000000000006010305010101000000000000000000000000000000000000030101030000000000000000000000000000000000000000000505010204010000000000000000000000000000000000000004010104030000000000000000000000000000000000000000050101020401000000000000000000000000000000000000000305040300000000000000000000000000000000000000000004020504010000000000000000000000000000000000000000050503010101000000000000000000000000000000000000000701020101010401000000000000000000000000000000000003010101000000000000000000000000000000000000000000')
    assert 625 == len(cowscan)
    cowscan = [[cowscan[i*25+j] for j in range(25)] for i in range(25)]
    
    def clean(v):
        u = []
        for w in v:
            print(w)
            leng = w[0]
            re = w[1:][:leng]
            oth = w[leng+1:]
            #assert oth == [0]*len(oth)
            u.append(re)
        return u
    
    linescan = clean(linescan)
    cowscan = clean(cowscan)
    print(linescan)
    print(cowscan)
    
    from z3 import *
    mat = [[Bool(f'x_{
            i},{
            j}') for j in range(25)] for i in range(25)]
    x = [[If(mat[i][j], 1, 0) for j in range(25)] for i in range(25)]
    lines = [0]*25
    linediff = [0]*25
    cows = [0]*25
    cowdiff = [0]*25
    sol = Solver()
    def valIn(a, b):
        if len(b) == 0:
            return False
        b = b.copy()
        cond = a == b[0]
        for i in range(1, len(b)):
            b[i] += b[i-1]
            cond = Or(cond, a==b[i])
        return cond
        
    
    for i in range(25):
        linediff[i] += x[i][0] + x[i][-1]
        cowdiff[i] += x[0][i] + x[-1][i]
        for j in range(24):
            linediff[i] += If(x[i][j] != x[i][j+1], 1, 0)
            cowdiff[i] += If(x[j][i] != x[j+1][i], 1, 0)
        for j in range(24):
            lines[i] += x[i][j]
            sol.add(Or(Or(x[i][j]!=1, x[i][j+1]!=0), valIn(lines[i], linescan[i])))
            cows[i] += x[j][i]
            sol.add(Or(Or(x[j][i]!=1, x[j+1][i]!=0), valIn(cows[i], cowscan[i])))
        for j in range(24, 25):
            lines[i] += x[i][j]
            cows[i] += x[j][i]
    
    for i in range(25):
        sol.add(lines[i] == sum(linescan[i]))
        sol.add(cows[i] == sum(cowscan[i]))
        sol.add(linediff[i] == 2*len(linescan[i]))
        sol.add(cowdiff[i] == 2*len(cowscan[i]))
    
    print('dd')
    print(sol.check())
    mod = sol.model()
    x = [[int(str(mod.eval(mat[i][j])) == 'True') for j in range(25)] for i in range(25)]
    y = '\n'.join(''.join(map(str, x[i])) for i in range(25))
    
    # 解中01Use spaces and  All black frame █ 替代:
    for c in y:
        if  c=='1':
            print('█',end='')
        elif c=='0':
            print(' ',end='')
        else:
            print()
    
    
    █████    █   ███ ██ █ █  
    █   █   █ █ █    █  █ █  
    ███ █   ███ █ ████  █ █  
    █   █  █   ██  █ █  █ █  
    █   ████   █ ███ ██ █ ███
                             
    ████   ████ ████   █ █ █ 
    █ ██   ██   █ ██  █ ██ █ 
    █ █ █ █ ███ ████  ███ █  
    █ █ █ █ █   █  █  █ █ █  
    ███  █  ███ █  ████ █ █  
          ██                 
       █  █    ████ █ █ ████ 
    ████████   █  █ █ █ ██  █
    █  █  █    █  █ █ █ ████ 
    ██ ██ █ ██ █  █  █ █ █  █
         ██    █████ █ █ ███ 
                             
    ████████████ ██  █ █ █ █ 
      ██ █  █  █  █  █ █ █ █ 
    ████ ███████  ██ █ █ █ █ 
    █  █ ██  █    █  █ █ █ █ 
    ████████████ ██          
                   █ █ █ █   
     ████   ██  █          █
    

    Notice that a bunch of empty columns are selectively turned into spaces(FLAG{I LOVE PLAY ctf_QWB2022})(The characters are well drawn,Don't draw next time)

    彩蛋?(The result of solving the fake array)

    ██        ██  
      ███      █ █      █ █  
     █████     █ ██    ██ █  
    █     █    █ ███   ██ █  
    █     █    ████████████  
    ███████    ██        ██  
    ██████    ██          ██ 
    █    █    █  ███    ██ █ 
    █   ██   █  █████  ████ █
    █████    █  ███ █  █ ████
    █████    █ ██████████████
    █   █   ██ ███   ████ ██ 
    █   █  █ █████    ██ ██  
    █████ ██     ██   ██ █   
    ███████       ██ ████    
    █    █         █████     
    █   ███            █   █ 
    ███████            ██  ██
     ████ ██            █████
     ██   ██        ██   ███ 
      █  ████        █████   
      █████ ███       █      
       ███  ██ █      █      
        ██  ██        ███    
         ████████████████
    

easyapk

javaThe layers are obfuscated but it is still easy to find the correct logic,native层调用的check函数, It's confusing insidetea加密,差不多长这样(前面还有4个key的生成):

  i = 0;
  p_tmp_seed = v173;
  while ( 1 )
  {
    
    p_len_1 = v179;
    *p_i = i;
    if ( i >= *p_len_1 )
      break;
    j = 0;
    input = *p_input;
    *p_p_input_i = &(*p_input)[i];
    *v182 = seeds;
    *p_l4b = *(_DWORD *)&input[i];
    *p_r4b = *(_DWORD *)&input[i + 4];
    *p_k = 0;
    v148 = time(0);
    p_seed2 = v174;
    p_seed3 = v175;
    p_seed1 = v176;
    v152 = (v148 & 0x30000000) - (v148 & 0xC0000000) + 2 * (v148 & 0x40000000) + 0x35970C13;
    p_l4b = v177;
    *p_tmp_seed = (v152 ^ 0xF4170810 | 0x1C88647) + 2 * (v152 ^ 0xBA075AA);
    seeds_1 = *v182;
    seed0 = **v182;
    *p_seed1 = seeds_1[1];
    *p_seed2 = seeds_1[2];
    *p_seed3 = seeds_1[3];
    while ( 1 )
    {
    
      *p_j = j;
      if ( j > 0x1F )
        break;
      r4b = *p_r4b;
      k = 2 * (*p_k | *p_tmp_seed) - (*p_tmp_seed ^ *p_k);
      *p_k = k;
      v156 = (2 * (k | r4b) - (k ^ r4b)) ^ (2 * (seed0 | (0x10 * r4b)) - (seed0 ^ (0x10 * r4b))) ^ (2 * (*p_seed1 | (r4b >> 5))
                                                                                                  - (*p_seed1 ^ (r4b >> 5)));
      seed2 = *p_seed2;
      enced_l4b = 2 * (v156 | *p_l4b) - (v156 ^ *p_l4b);
      *p_l4b = enced_l4b;
      v159 = (2 * (*p_seed3 | (enced_l4b >> 5)) - (*p_seed3 ^ (enced_l4b >> 5))) ^ (2 * (seed2 | (0x10 * enced_l4b))
                                                                                  - (seed2 ^ (0x10 * enced_l4b))) ^ (2 * (enced_l4b | *p_k) - (*p_k ^ enced_l4b));
      *p_r4b = 2 * (v159 | *p_r4b) - (v159 ^ *p_r4b);
      j = (*p_j | 0xFFFFFFFE) - (*p_j & 0xFFFFFFFE) + 2 * (*p_j | 1) + 1;// j ++
    }
    p_i = v178;
    p_input_i = *p_p_input_i;
    *p_input_i = *p_l4b;
    p_input_i[1] = *p_r4b;
    i = (*p_i | 0xFFFFFFF7) - (*p_i & 0xFFFFFFF7) + 2 * (*p_i | 8) + 1;// i+=8
  }

The final decrypted output also needs to be decrypted by Virginia,密钥是n.

#include <stdio.h> 
#include <stdint.h> 
void decrypt (uint32_t v[2],const uint32_t k[4]) {
    
    uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;/* set up; sum is (delta << 5) & 0xFFFFFFFF */
		uint32_t delta=0x9E3779B9;/* a key schedule constant */
		uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];/* cache key */
		for (i=0; i<32; i++) {
    
				v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
        v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
        sum -= delta;
    }
		v[0]=v0; v[1]=v1;
}
int main()  
{
      
    uint32_t v[9]= {
    0x5D94AA84, 0x14FA24A0, 0x2B560210, 0xB69BDD49, 0xAAEFEAD4, 0x4B8CF4C6, 0x097FB8C9, 0xB5EC51D2,0};  
    uint32_t const k[4]= {
    0x33323130,0x37363534,0x62613938,0x66656463};  
    for(int i=0;i<4;i++){
    
        decrypt(&v[2*i],k);
    }
    printf("%s\n",v);
    return 0;  
}
原网站

版权声明
本文为[1mmorta1]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/222/202208100151177984.html