当前位置:网站首页>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
- 由于有root检测和frida检测,换个端口启动 ./frida-server-15.1.8-android-arm64 -l 0.0.0.0:27049
- 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.
通过scoreboard http://47.93.244.181/re/ScoreBoard.php Find a high scoreadmin "IbaoQT/3eTXIjHDJ2L5TQE==”(a.k.a. admin)
Obtained by adding friendsadmin的account $.post(‘AddFriend.php’, {code:‘123125’})

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

easyre
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.
使用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
Hardware breakpoints on and off the two arrays to be compared,Notice that the subroutine starts by swapping the last two arrays compared.
用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;
}
边栏推荐
猜你喜欢
随机推荐
牛客刷题——剑指offer(第四期)
【LeetCode】求根节点到叶节点数字之和
SQL注入的order by ,limit与宽字节注入
flask增删改查
高压之下,必有懦夫
RESOURCE_EXHAUSTED: etcdserver: mvcc: database space exceeded
【web渗透】SSRF漏洞超详细讲解
【干货】集成学习原理总结
Premint工具,作为普通人我们需要了解哪些内容?
c# 解决CS8602告警 解引用可能出现空引用
已备案域名用国外服务器会不会掉备案?
首次在我们的centos登录我们的Mysql
ImportError: Unable to import required dependencies: numpy
JCMsuite—单模光纤传播模式
Shader Graph learns various special effects cases
.Net interview experience summary
中文NER的SOTA:RICON
LeetCode 每日一题——1413. 逐步求和得到正数的最小值
[QNX Hypervisor 2.2用户手册]10.14 smmu
多线程之享元模式和final原理









