当前位置:网站首页>2022强网杯 Quals Reverse 部分writeup
2022强网杯 Quals Reverse 部分writeup
2022-08-10 01:51:00 【1mmorta1】
Game
native层其实只有加解密的两个函数,所以没怎么逆,直接用frida hook
- 由于有root检测和frida检测,换个端口启动 ./frida-server-15.1.8-android-arm64 -l 0.0.0.0:27049
- 然后就可以直接调用加解密函数了:
/* 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"
主要还是在逆java层的逻辑,所有数据都是在和47.93.244.181服务器进行交互,因此只要在com.silence.scoreboard.http.HttpRequest 里逆清楚几个交互的逻辑就行。
通过scoreboard http://47.93.244.181/re/ScoreBoard.php 找到高分admin "IbaoQT/3eTXIjHDJ2L5TQE==”(a.k.a. admin)
通过加好友获得admin的account $.post(‘AddFriend.php’, {code:‘123125’})

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

easyre
通过读主程序可知,程序写一个子程序re3并ptrace它,在遇到中断的时候会根据RIP的内容解密、重新加密某一段代码。
使用strace获得所有系统调用,(所有对子程序的写操作都通过ptrace实现),解析PTRACE_POKETEXT并patch程序(仅限解密部分)
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和longjmp部分代码应该只是写了一个循环比较的过程
在要比较的两个数组上下硬件断点,注意到子程序开始会将最后两个比较的数组偷换。
用z3求解对应问题(队内4老师的脚本!我菜菜是自己手画的55):
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)) # 解中01分别用空格与 全黑框 █ 替代: for c in y: if c=='1': print('█',end='') elif c=='0': print(' ',end='') else: print()█████ █ ███ ██ █ █ █ █ █ █ █ █ █ █ ███ █ ███ █ ████ █ █ █ █ █ ██ █ █ █ █ █ ████ █ ███ ██ █ ███ ████ ████ ████ █ █ █ █ ██ ██ █ ██ █ ██ █ █ █ █ █ ███ ████ ███ █ █ █ █ █ █ █ █ █ █ █ ███ █ ███ █ ████ █ █ ██ █ █ ████ █ █ ████ ████████ █ █ █ █ ██ █ █ █ █ █ █ █ █ ████ ██ ██ █ ██ █ █ █ █ █ █ ██ █████ █ █ ███ ████████████ ██ █ █ █ █ ██ █ █ █ █ █ █ █ █ ████ ███████ ██ █ █ █ █ █ █ ██ █ █ █ █ █ █ ████████████ ██ █ █ █ █ ████ ██ █ █注意到一堆空列里有选择性地变成空格(FLAG{I LOVE PLAY ctf_QWB2022})(字符画画的很好,下次别画了)
彩蛋?(假数组求解的结果)
██ ██ ███ █ █ █ █ █████ █ ██ ██ █ █ █ █ ███ ██ █ █ █ ████████████ ███████ ██ ██ ██████ ██ ██ █ █ █ ███ ██ █ █ ██ █ █████ ████ █ █████ █ ███ █ █ ████ █████ █ ██████████████ █ █ ██ ███ ████ ██ █ █ █ █████ ██ ██ █████ ██ ██ ██ █ ███████ ██ ████ █ █ █████ █ ███ █ █ ███████ ██ ██ ████ ██ █████ ██ ██ ██ ███ █ ████ █████ █████ ███ █ ███ ██ █ █ ██ ██ ███ ████████████████
easyapk
java层被混淆了但还是很简单就能找到正确的逻辑,native层调用的check函数, 里面是混淆过的tea加密,差不多长这样(前面还有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
}
最后解密得到的输出还需要进行维吉尼亚解密,密钥是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;
}
边栏推荐
- OpenCV图像处理学习三,Mat对象构造函数与常用方法
- 【wpf】拖拽的简单实现
- Unity editor extension interface uses List
- 常用正则备查
- ImportError: Unable to import required dependencies: numpy
- QT中,QTableWidget 使用示例详细说明
- 《GB39732-2020》PDF下载
- [Turn] Typora_Markdown_ picture title (caption)
- 【干货】集成学习原理总结
- [LeetCode] Find the sum of the numbers from the root node to the leaf node
猜你喜欢

微透镜阵列的高级模拟

Unity vertex animation

unity 报错 Unsafe code may only appear if compiling with /unsafe. Enable “Allow ‘unsafe‘ code“ in Pla

781. 森林中的兔子

SQL注入的order by ,limit与宽字节注入

Sikuli's Automated Testing Technology Based on Pattern Recognition

Screen 拆分屏幕

程序员的专属浪漫——用3D Engine 5分钟实现烟花绽放效果

免费文档翻译软件电脑版软件

OpenCV图像处理学习三,Mat对象构造函数与常用方法
随机推荐
Teach you how to write performance test cases
odoo公用变量或数组的使用
你有对象类,我有结构体,Go lang1.18入门精炼教程,由白丁入鸿儒,go lang结构体(struct)的使用EP06
夏克-哈特曼波前传感器
Experimental support for decorators may change in future releases.Set the "experimentalDecorators" option in "tsconfig" or "jsconfig" to remove this warning
微透镜阵列后光传播的研究
墨西哥大众VW Mexico常见的几种label
Initial attempt at UI traversal
C# rounding MidpointRounding.AwayFromZero
Janus实际生产案例
具有多孔光纤的偏振分束器
【QT】QT项目:自制Wireshark
中英文互译在线翻译-在线翻译软件
【引用计数器及学习MRC的理由 Objective-C语言】
空间复杂度为O(1)的归并排序
手把手教你编写性能测试用例
Under pressure, there must be cowards
LeetCode 每日一题——1413. 逐步求和得到正数的最小值
Chip Information|Semiconductor revenue growth expected to slow to 7%, Bluetooth chip demand still growing steadily
STM32F103驱动HCSR04超声波测距显示