资源链接https://download.csdn.net/download/alickxc/11705813
1.CISCN-2018 Illusion:
首先查看关键点:
可以看出app通过对用户输入数据加密并比较的方式判断flag准确性,再查看so实现,
首先JNI_Onload():
获得加密函数地址:
这里函数翻译有误因为函数调推测并非C语言实现有着工整的开场白和结束语而是内联汇编实现的:
关键点是10AC函数进去看了下有着简单的位移计算并无外部引用,所以我们只要算出0x1-0xff的函数mapping返回数据再根据ASCII码剔除无关分支就能拿到Flag所以我们上手编写模拟程序:
# coding=utf-8
import logging
import ctypes
from unicorn.arm_const import UC_ARM_REG_R0,UC_ARM_REG_R1,UC_ARM_REG_R2,UC_ARM_REG_R3,UC_ARM_REG_PC,UC_ARM_REG_R6,UC_ARM_REG_SP
from unicorn import Uc,UC_ARCH_ARM,UC_MODE_THUMB,UC_PROT_ALL,UC_HOOK_CODE,UcError
UC_MEM_ALIGN = 0x1000
def align(addr, size, growl):
to = ctypes.c_uint64(UC_MEM_ALIGN).value
mask = ctypes.c_uint64(0xFFFFFFFFFFFFFFFF).value ^ ctypes.c_uint64(to - 1).value
right = addr + size
right = (right + to - 1) & mask
addr &= mask
size = right - addr
if growl:
size = (size + to - 1) & mask
return addr, size
def hook_code(uc, address, size, user_data):
# print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
pass
if __name__ == "__main__":
module_base = 0x1000000
simulator = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
with open('/Users/user/ElongDev/testWorkspace/encryptTest/Illusion/libnative-lib.so','rb') as fstream:
lib_bytes = fstream.read()
filesize = len(lib_bytes)
(address,size) = align(module_base,filesize,True);
simulator.mem_map(address,size,UC_PROT_ALL)
simulator.mem_write(address,lib_bytes)
simulator.mem_map(0x800000, 0x1000, UC_PROT_ALL)
simulator.reg_write(UC_ARM_REG_SP,0x801000)
for i in range(1,256):
simulator.reg_write(UC_ARM_REG_R0,i)
simulator.reg_write(UC_ARM_REG_R1,93)
start_address = module_base+0x10c0+1
end_address = start_address+0x10-1
simulator.hook_add(UC_HOOK_CODE, hook_code, start_address, end_address)
simulator.emu_start(start_address,end_address)
ret = simulator.reg_read(UC_ARM_REG_R1)+0x20
print("%d,%d"%(i,ret))
pass
pass
pass
public static void main(String[] args) throws Exception{
// String gb = new String(,"GB2312");
String tmp = "1,33$2,34$3,35$4,36$5,37$6,38$7,39$8,40$9,41$10,42$11,43$12,44$13,45$14,46$15,47$16,48$17,49$18,50$19,51$20,52$21,53$22,54$23,55$24,56$25,57$26,58$27,59$28,60$29,61$30,62$31,63$32,64$33,65$34,66$35,67$36,68$37,69$38,70$39,71$40,72$41,73$42,74$43,75$44,76$45,77$46,78$47,79$48,80$49,81$50,82$51,83$52,84$53,85$54,86$55,87$56,88$57,89$58,90$59,91$60,92$61,93$62,94$63,95$64,96$65,97$66,98$67,99$68,100$69,101$70,102$71,103$72,104$73,105$74,106$75,107$76,108$77,109$78,110$79,111$80,112$81,113$82,114$83,115$84,116$85,117$86,118$87,119$88,120$89,121$90,122$91,123$92,124$93,32$94,33$95,34$96,35$97,36$98,37$99,38$100,39$101,40$102,41$103,42$104,43$105,44$106,45$107,46$108,47$109,48$110,49$111,50$112,51$113,52$114,53$115,54$116,55$117,56$118,57$119,58$120,59$121,60$122,61$123,62$124,63$125,64$126,65$127,66$128,67$129,68$130,69$131,70$132,71$133,72$134,73$135,74$136,75$137,76$138,77$139,78$140,79$141,80$142,81$143,82$144,83$145,84$146,85$147,86$148,87$149,88$150,89$151,90$152,91$153,92$154,93$155,94$156,95$157,96$158,97$159,98$160,99$161,100$162,101$163,102$164,103$165,104$166,105$167,106$168,107$169,108$170,109$171,110$172,111$173,112$174,113$175,114$176,115$177,116$178,117$179,118$180,119$181,120$182,121$183,122$184,123$185,124$186,32$187,33$188,34$189,35$190,36$191,37$192,38$193,39$194,40$195,41$196,42$197,43$198,44$199,45$200,46$201,47$202,48$203,49$204,50$205,51$206,52$207,53$208,54$209,55$210,56$211,57$212,58$213,59$214,60$215,61$216,62$217,63$218,64$219,65$220,66$221,67$222,68$223,69$224,70$225,71$226,72$227,73$228,74$229,75$230,76$231,77$232,78$233,79$234,80$235,81$236,82$237,83$238,84$239,85$240,86$241,87$242,88$243,89$244,90$245,91$246,92$247,93$248,94$249,95$250,96$251,97$252,98$253,99$254,100$255,101";
Map> map = new HashMap<>();
for(String str:tmp.split("\\$")){
String key = str.split(",")[1];
String value = str.split(",")[0];
Set set = map.get(key);
if(set == null)set = new HashSet<>();
set.add(value);
map.put(key,set);
}
byte[] bytes = "Ku@'G_V9v(yGS".getBytes("GB2312");
byte[] table = "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;".getBytes();
for(int i=0;i s = map.get(String.valueOf((int)b));
for(String str:s){
int ifo = Integer.parseInt(str)-table[i]+64;
if(ifo>32&&ifo<128) {
char c = (char) ifo;
System.out.print(c);
}
}
// System.out.println();
}
System.out.println(bytes);
}
最终拿到Flag:CISCN{GJ5728}
2.GCTF05-Mobile:
首先查看关键代码:
流程很简单通过Handler创建一个休息1s的定时任务不过按原App的逻辑我们需要等200000s才能拿到结果...所以需要自己写脚本判断K的值:
public static boolean is2(int n) {
if (n <= 3) {
if (n > 1) {
return true;
}
return false;
} else if (n % 2 == 0 || n % 3 == 0) {
return false;
} else {
int i = 5;
while (i * i <= n) {
if (n % i == 0 || n % (i + 2) == 0) {
return false;
}
i += 6;
}
return true;
}
}
public static void aliTime(){
int beg = 200000;
int k = 0;
int now;
long t1 = 0;
long t2 = 0;
while(true){
t1 += t2;
now = (int) (t1 / 1000);
t2 = 1500 - (t1 % 1000);
if(beg<=now){
System.out.println(k);
return;
}
if (is2(beg - now)) {
k += 100;
} else {
k--;
}
}
}
计算结束后拿到K的值:1616384
so用unicorn-engine跑一下即可获得flag
3.***CTF-Android2:
首先查看Activity
明显so题目查看so代码:
易知加密分为4步:init(将字符串分组)->First->亦或块1->亦或块2。
既然是亦或操作那逆向逻辑就很简单了:
public static void android2(){
byte[] bytes = "LN^dl".getBytes();
byte[] a0 = new byte[5];
for(int i=0;i<= 4;i++){
if(i == 4){
a0[i] = bytes[4];
continue;
}
a0[i] = (byte) ((bytes[i]^0x80)/2&0xff);
}
System.out.println(new String(a0));
byte[] bytes1 = new byte[]{0x20,0x35,0x2d,0x16,0x61};
byte[] a1 = new byte[5];
for(int i=0;i
求出此题Flag:flag{sosorryla}
4.CISCN-2018 TryGetFlag:
打开文件发现爱加密壳...我们考虑直接内存dump dex吧 不会让人手工脱爱加密吧....
IDA附加程序可以再module框看到odex文件,直接dump出来:
查看smali代码逻辑,Base64+AES特征明显: