题目地址
分析
解包,查看java层核心逻辑
if ((MainActivity.this.checkFirst(paramAnonymousView)) && (MainActivity.this.checkSecond(paramAnonymousView))) {
Toast.makeText(MainActivity.this, "注册成功!", 0).show();
} else {
Toast.makeText(MainActivity.this, "注册失败!", 0).show();
}
其中checkSecond
函数为so层里的。
public native boolean checkSecond(String paramString);
checkFirst
函数限制了注册码为16位,且为1-8的数字
private boolean checkFirst(String paramString)
{
if (paramString.length() != 16) {
return false;
}
int i = 0;
while (i < paramString.length()) {
if ((paramString.charAt(i) <= '8') && (paramString.charAt(i) >= '1')) {
i++;
} else {
return false;
}
}
return true;
}
看到so层的校验函数有两个
if ( checkfirst((__int64)&v7) & 1 )
{
std::__ndk1::basic_string<char,std::__ndk1::char_traits<char>,std::__ndk1::allocator<char>>::basic_string(&v6, &v8);
v5 = 1;
v4 = checkAgain((__int64)&v6);
}
其中checkfirst
要求注册码以12345678开头,checkAgain
要求注册码为12345678数字的某种排列,注册码总共16位。
最终EXP
# libnative-lib.so
import angr
import claripy
import binascii
base = 0x400000
p = angr.Project("./libnative-lib.so")
key = claripy.BVS("key", 16 * 8)
state = p.factory.blank_state(addr=0xECC0+base)
# 0xF19C + base :first_out_call
# 0xF198 check_first_wrapper
# 0xE3C0 check_first
# 0xECC0 check_again
# for i in range(0, 8):
# state.add_constraints(key.get_byte(i) == claripy.BVV(i + ord('1'), 4))
# state.se.add(key.get_byte(8) == int(binascii.hexlify(b"12345678"), 16))
state.se.add(key.get_byte(0) == int(binascii.hexlify(b"1"), 16))
state.se.add(key.get_byte(1) == int(binascii.hexlify(b"2"), 16))
state.se.add(key.get_byte(2) == int(binascii.hexlify(b"3"), 16))
state.se.add(key.get_byte(3) == int(binascii.hexlify(b"4"), 16))
state.se.add(key.get_byte(4) == int(binascii.hexlify(b"5"), 16))
state.se.add(key.get_byte(5) == int(binascii.hexlify(b"6"), 16))
state.se.add(key.get_byte(6) == int(binascii.hexlify(b"7"), 16))
state.se.add(key.get_byte(7) == int(binascii.hexlify(b"8"), 16))
sm = p.factory.simulation_manager(state)
sm.explore(find=[ # 0xE607 + base, # first_check
# 0xE487 + base, # char+1
# 0xE4E4 + base, # cahr+1
0xF0F5 + base,
#0xF223 + base # out of check_second , in check_main
],
avoid=[0xE5E2 + base, # check_first
0xF00F + base, 0xF037 + base, 0xF0B7 + base, 0xF077 + base, 0xEFB4 + base, 0xEF9C + base,
0xEF81 + base,
0xF22C+base # behind calculation
]) #
found = sm.found[0]
for i in range(8, 16):
cond_0 = key.get_byte(i) >= ord('1')
cond_1 = key.get_byte(i) <= ord('8')
found.add_constraints(found.solver.And(cond_0, cond_1))
for j in range(i + 1, 16):
if i == j or j >= 16:
break
# found.add_constraints(found.solver.And(key.get_byte(i) != key.get_byte(j), cond_1))
# print("NOW ADD index(%d) !=index(%d)", i, j)
cond2 = key.get_byte(i) != key.get_byte(j)
found.add_constraints(found.solver.And(cond_0, cond2))
# if i + 1 <= 17:
# cond_2 = key.get_byte(i) != key.get_byte(i + 1)
# found.add_constraints(found.solver.And(cond_0, cond_2))
tmp_addr = 0x38460 + base
state.regs.rdi = tmp_addr
flag_addr = state.regs.rdi
# found.add_constraints(found.memory.load(flag_addr, 5) == int(binascii.hexlify(b"12345678"), 16))
found.memory.store(flag_addr, key)
if found.solver.satisfiable():
print("FIND IT")
else:
print("CANNOT FIND")
exit(0)
flag_str = found.solver.eval(key, cast_to=bytes)
print(bytes.decode(flag_str).strip('\x00'))
跑了几分钟后的结果
FIND IT
1234567853267418
注意点(PS)
基址
这里so文件的加载基址在angr刚装载的时候有提示
WARNING | cle.loader | The main binary is a position-independent executable. It is being loaded with a base address of 0x400000.
所以我们后面程序的地址要加上基址偏移。
angr用法注意点
- 内存读入与写入
found.memory.store(flag_addr, key) #key是要写入的数值
res=found.memory.load(flag_addr, YourWantedLength) # res是一个int类型的数字,判断比较的时候常用int(binascii.hexlify(b"TargetStr"), 16)
- 符号条件
cond_0 = key.get_byte(i) >= ord('1')
cond_1 = key.get_byte(i) <= ord('8')
found.add_constraints(found.solver.And(cond_0, cond_1)) #其实found.solver.And(cond_0, cond_1)也是一个条件cond,可以作为子类再次参与逻辑运算
state.se.add(key.get_byte(0) == int(binascii.hexlify(b"1"), 16))
- 处理结果
判断是否有解
if found.solver.satisfiable():
结果的输出
flag_str = found.solver.eval(key, cast_to=bytes)
print(bytes.decode(flag_str).strip('\x00'))
Comments | NOTHING