这次带着自己弱校队伍打了个第十,院校队真卷。
做了三题,大半夜做题脑子着实跟不上,shellcode被ror13迷惑了一万年……
解题过程写的比较笼统,逐渐变懒orz…
fpbe
bpf program
libbpf/libbpf.h at master · libbpf/libbpf (github.com)
/** * @brief **bpf_program__attach_uprobe()** attaches a BPF program * to the userspace function which is found by binary path and * offset. You can optionally specify a particular proccess to attach * to. You can also optionally attach the program to the function * exit instead of entry. * * @param prog BPF program to attach * @param retprobe Attach to function exit * @param pid Process ID to attach the uprobe to, 0 for self (own process), * -1 for all processes * @param binary_path Path to binary that contains the function symbol * @param func_offset Offset within the binary of the function symbol * @return Reference to the newly created BPF link; or NULL is returned on error, * error code is stored in errno */ LIBBPF_API struct bpf_link * bpf_program__attach_uprobe(const struct bpf_program *prog, bool retprobe, pid_t pid, const char *binary_path, size_t func_offset);
使用bpftool dump出ir和流程图
> bpftool prog show 259: kprobe name uprobe tag d833ddf75360d0b4 gpl loaded_at 2022-03-19T11:15:32+0800 uid 0 xlated 792B jited 607B memlock 4096B > bpftool prog dump xlated id 259 ··· > bpftool prog dump xlated id 259 visual &> output.out > dot -Tpng output.out -o visual-graph.png
脚本生成伪代码
data = """ 0: (79) r2 = *(u64 *)(r1 +104) 1: (67) r2 <<= 32 2: (77) r2 >>= 32 ... """ av = [] for line in data.splitlines(): if "goto" in line: t = line.split("goto") condtion, gotoLine = t[0].split("if")[1], f'goto _{str(int(line[:4]) + int(t[1].split("+")[1]) + 1)}' av.append("_"+line[:6].strip(" ") + f"if({condtion})" + '{' + gotoLine + ';}') else: av.append("_"+line[:6].strip(" ")+line[10:]+";") print("\n".join(av))
重编译
#include <cstdint> #include <cstdio> #include <string> typedef uint64_t u64; typedef uint8_t u8; typedef uint32_t u32; int main() { u64 flag[4] = {0,1,2,3}; u64 r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10; _0: r2 = *(u64 *)flag[2]; _1: r2 <<= 32; _2: r2 >>= 32; _3: r3 = *(u64 *)flag[3]; _4: r3 <<= 32; _5: r3 >>= 32; _6: r4 = r3; _7: r4 *= 28096; _8: r5 = r2; _9: r5 *= 64392; _10: r5 += r4; _11: r4 = *(u64 *)flag[1]; _12: r4 <<= 32; _13: r4 >>= 32; _14: r0 = r4; _15: r0 *= 29179; _16: r5 += r0; _17: r1 = *(u64 *)flag[0]; _18: r0 = 0; _19: *(u8 *)(r10 -8) = r0; _20: *(u64 *)(r10 -16) = r0; _21: *(u64 *)(r10 -24) = r0; _22: r1 <<= 32; _23: r1 >>= 32; _24: r0 = r1; _25: r0 *= 52366; _26: r5 += r0; _27: r6 = 1; _28: r0 = 0xbe18a1735995; _30:if( r5 != r0 ){goto _97;} _31: r5 = r3; _32: r5 *= 61887; _33: r0 = r2; _34: r0 *= 27365; _35: r0 += r5; _36: r5 = r4; _37: r5 *= 44499; _38: r0 += r5; _39: r5 = r1; _40: r5 *= 37508; _41: r0 += r5; _42: r5 = 0xa556e5540340; _44:if( r0 != r5 ){goto _97;} _45: r5 = r3; _46: r5 *= 56709; _47: r0 = r2; _48: r0 *= 32808; _49: r0 += r5; _50: r5 = r4; _51: r5 *= 25901; _52: r0 += r5; _53: r5 = r1; _54: r5 *= 59154; _55: r0 += r5; _56: r5 = 0xa6f374484da3; _58:if( r0 != r5 ){goto _97;} _59: r5 = r3; _60: r5 *= 33324; _61: r0 = r2; _62: r0 *= 51779; _63: r0 += r5; _64: r5 = r4; _65: r5 *= 31886; _66: r0 += r5; _67: r5 = r1; _68: r5 *= 62010; _69: r0 += r5; _70: r5 = 0xb99c485a7277; _72:if( r0 != r5 ){goto _97;} _73: *(u32 *)(r10 -12) = r1; _74: *(u32 *)(r10 -16) = r4; _75: *(u32 *)(r10 -20) = r2; _76: *(u32 *)(r10 -24) = r3; _77: r1 = 0xa7d73257b465443; _79: *(u64 *)(r10 -40) = r1; _80: r1 = 0x4648203a47414c46; _82: *(u64 *)(r10 -48) = r1; _83: r1 = 0x2052554f59202145; _85: *(u64 *)(r10 -56) = r1; _86: r1 = 0x4e4f44204c4c4557; _88: *(u64 *)(r10 -64) = r1; _89: r6 = 0; _90: *(u8 *)(r10 -32) = r6; _91: r1 = r10; _92: r1 += -64; _93: r3 = r10; _94: r3 += -24; _95: r2 = 33; _96:printf((char*)r1, r3); _97: r0 = r6; _98: exit; printf("\n"); return 0; }
hex-rays decompiler
线性方程组求解
from z3 import * MEMORY = [BitVec(f"MEMORY{i}", 64) for i in range(4)] sol = Solver() sol.add(52366 * MEMORY[0] + 29179 * MEMORY[1] + 28096 * MEMORY[3] + 64392 * MEMORY[2] == 0xBE18A1735995) sol.add(37508 * MEMORY[0] + 44499 * MEMORY[1] + 61887 * MEMORY[3] + 27365 * MEMORY[2] == 0xA556E5540340) sol.add(59154 * MEMORY[0] + 25901 * MEMORY[1]+ 56709 * MEMORY[3] + 32808 * MEMORY[2] == 0xA6F374484DA3) sol.add(62010 * MEMORY[0] + 31886 * MEMORY[1] + 33324 * MEMORY[3] + 51779 * MEMORY[2] == 0xB99C485A7277) assert sol.check() == sat mol = sol.model() print(''.join([int.to_bytes(mol.eval(i).as_long(), length=8, byteorder="little")[:4].decode() for i in MEMORY][::-1]))
Contra 2048
表面上是个2048
用了webview 走的JavascriptInterface,gamemanager.js
加了混淆
native加了微量ollvm bcf和fla,外加字符串混淆
frida hook dump出so
看到一堆anti-debug
从pcap入手
分析消息的格式
struct msg { _DWORD header; _DWORD type; _DWORD time; _DWORD hash; _DWORD flag; BYTE data[32]; };
重点关注类型type = 2
data组成如下
- 4 bytes nums (
0xdead + index
) - 1 bytes input
- zero padding
解析消息,获得密文
from construct import * from Crypto.Cipher import AES st = Struct( Const(b"HUFU"), "type" / Int32ul, "time" / Int32ul, "hash_0" / Hex(Int32ul), "flag" / Int32ul, "data" / Select(Bytes(32), Hex(Int64ul)), ) peer0 = [[]] * 51 peer0[0] = [ # Packet 1 0x48, 0x55, 0x46, 0x55, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x81, 0x13, 0x62, 0xcd, 0xd7, 0x40, 0x15, 0x20, 0x00, 0x00, 0x00, 0x62, 0x73, 0x6f, 0x54, 0x49, 0x4e, 0x58, 0x66, 0x50, 0x66, 0x58, 0x5a, 0x70, 0x51, 0x5a, 0x72, 0x65, 0x41, 0x4d, 0x75, 0x77, 0x73, 0x61, 0x56, 0x50, 0x75, 0x65, 0x6f, 0x6e, 0x72, 0x73, 0x47 ] # ··· arrs = [bytearray(i) for i in peer0] valueArr = [] for i in range(len(arrs)): data = arrs[i] p = st.parse(data) print(f"{i}:", p) if p["data"][0] == 0xff: ctx = AES.new(key=b"KZoLJZlLkRlMOtuD", mode=AES.MODE_ECB) value = p["data"][1:17] dec = ctx.decrypt(value) if dec[1] == 0xde: valueArr.append(dec) print("aesdec", dec.hex(), value.hex()) print(([i[4] for i in valueArr]))
在gamemanager.js
能看到首先对输入xtea,而后变表base64传入native调用check
相同check首先base64解码,而后魔改sbox aes加密
找到aes key和xtea key逆过程解密
#include <cstdint> #include <cstdio> #include <string> #define AES_BLOCK_SIZE 16 #define AES_ROUNDS 10 // 12, 14 #define AES_ROUND_KEY_SIZE 176 // AES-128 has 10 rounds, and there is a AddRoundKey before first round. (10+1)x16=176. /* * round constants */ static uint8_t RC[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36}; /* * Sbox */ static uint8_t SBOX[256] = { 0xFC, 0xA1, 0xC1, 0x37, 0x3B, 0x43, 0x15, 0xDE, 0x7E, 0x24, 0x22, 0xEA, 0x62, 0xC2, 0x9F, 0x8F, 0xA0, 0x3D, 0xF0, 0x05, 0xA9, 0x7B, 0x74, 0x50, 0xB9, 0x71, 0x58, 0x0F, 0xE1, 0x21, 0xB0, 0x85, 0x25, 0x8D, 0x6A, 0x97, 0x91, 0x3F, 0xAD, 0x6D, 0xB7, 0xB4, 0xD0, 0x2C, 0x0C, 0x56, 0x7A, 0xAB, 0x0A, 0x5B, 0x83, 0xC5, 0xD6, 0x52, 0xB6, 0x88, 0xC0, 0xC4, 0x5F, 0x92, 0xBC, 0xE2, 0x1A, 0x4D, 0x76, 0x1F, 0x89, 0x1C, 0x23, 0xDF, 0xCA, 0x60, 0xE0, 0x17, 0x36, 0x75, 0xA7, 0x9E, 0x14, 0x5A, 0x02, 0x46, 0x4A, 0x11, 0x2F, 0x8B, 0xF4, 0x33, 0xF2, 0x6E, 0x72, 0xA5, 0xC7, 0xE3, 0xDA, 0x38, 0x53, 0x9B, 0x87, 0x09, 0x01, 0x4B, 0xA4, 0x42, 0x2E, 0xE7, 0x3A, 0x84, 0x12, 0x7F, 0x07, 0xBE, 0xC8, 0xC9, 0x13, 0x47, 0xFE, 0xD1, 0xAC, 0xF6, 0xF1, 0xA8, 0x96, 0xB2, 0xC6, 0x18, 0xFB, 0xD4, 0x82, 0x16, 0x73, 0x64, 0x5E, 0x7D, 0xEF, 0x0E, 0xAE, 0xA2, 0x0B, 0x30, 0xF7, 0xDD, 0xA6, 0x29, 0x6C, 0xDC, 0x98, 0xFA, 0xBD, 0x67, 0xD5, 0xD8, 0xAF, 0x51, 0xE4, 0xBF, 0x65, 0x1D, 0xF8, 0xCE, 0x9C, 0x26, 0xF3, 0x2A, 0x9A, 0x45, 0x08, 0x5C, 0x57, 0x06, 0x54, 0x2B, 0x41, 0x70, 0xB1, 0x63, 0x66, 0x3C, 0x44, 0x10, 0x31, 0x19, 0x86, 0x61, 0x6B, 0xD7, 0x79, 0xCB, 0x81, 0x69, 0x0D, 0xD2, 0xFF, 0x2D, 0x40, 0x03, 0x90, 0x9D, 0xE9, 0x4C, 0xCD, 0x00, 0xE5, 0x80, 0xDB, 0xBA, 0xCF, 0x48, 0xD9, 0x3E, 0xFD, 0x4F, 0xEE, 0x8E, 0x4E, 0x77, 0xA3, 0xB5, 0x5D, 0x32, 0xE6, 0x68, 0x27, 0xAA, 0xE8, 0x55, 0xF5, 0xCC, 0x78, 0x6F, 0xD3, 0x93, 0x7C, 0x28, 0x99, 0x34, 0xB3, 0x04, 0x95, 0x49, 0xED, 0x8A, 0xF9, 0x1E, 0xB8, 0xC3, 0x8C, 0x59, 0xEB, 0xEC, 0x35, 0x39, 0xBB, 0x1B, 0x94, 0x20}; /* * Inverse Sboxs */ static uint8_t INV_SBOX[256] = { 0xc9, 0x64, 0x50, 0xc3, 0xed, 0x13, 0xa9, 0x6e, 0xa6, 0x63, 0x30, 0x8a, 0x2c, 0xbe, 0x87, 0x1b, 0xb3, 0x53, 0x6c, 0x72, 0x4e, 0x06, 0x81, 0x49, 0x7d, 0xb5, 0x3e, 0xfd, 0x43, 0x9d, 0xf3, 0x41, 0xff, 0x1d, 0x0a, 0x44, 0x09, 0x20, 0xa1, 0xde, 0xe9, 0x8f, 0xa3, 0xab, 0x2b, 0xc1, 0x68, 0x54, 0x8b, 0xb4, 0xdb, 0x57, 0xeb, 0xfa, 0x4a, 0x03, 0x5f, 0xfb, 0x6a, 0x04, 0xb1, 0x11, 0xd1, 0x25, 0xc2, 0xac, 0x67, 0x05, 0xb2, 0xa5, 0x51, 0x73, 0xcf, 0xef, 0x52, 0x65, 0xc7, 0x3f, 0xd6, 0xd3, 0x17, 0x99, 0x35, 0x60, 0xaa, 0xe1, 0x2d, 0xa8, 0x1a, 0xf7, 0x4f, 0x31, 0xa7, 0xda, 0x84, 0x3a, 0x47, 0xb7, 0x0c, 0xaf, 0x83, 0x9c, 0xb0, 0x95, 0xdd, 0xbd, 0x22, 0xb8, 0x90, 0x27, 0x59, 0xe5, 0xad, 0x19, 0x5a, 0x82, 0x16, 0x4b, 0x40, 0xd7, 0xe4, 0xba, 0x2e, 0x15, 0xe8, 0x85, 0x08, 0x6d, 0xcb, 0xbc, 0x80, 0x32, 0x6b, 0x1f, 0xb6, 0x62, 0x37, 0x42, 0xf1, 0x55, 0xf6, 0x21, 0xd5, 0x0f, 0xc4, 0x24, 0x3b, 0xe7, 0xfe, 0xee, 0x7a, 0x23, 0x92, 0xea, 0xa4, 0x61, 0xa0, 0xc5, 0x4d, 0x0e, 0x10, 0x01, 0x89, 0xd8, 0x66, 0x5b, 0x8e, 0x4c, 0x79, 0x14, 0xdf, 0x2f, 0x76, 0x26, 0x88, 0x98, 0x1e, 0xae, 0x7b, 0xec, 0x29, 0xd9, 0x36, 0x28, 0xf4, 0x18, 0xcd, 0xfc, 0x3c, 0x94, 0x6f, 0x9b, 0x38, 0x02, 0x0d, 0xf5, 0x39, 0x33, 0x7c, 0x5c, 0x70, 0x71, 0x46, 0xbb, 0xe3, 0xc8, 0x9f, 0xce, 0x2a, 0x75, 0xbf, 0xe6, 0x7f, 0x96, 0x34, 0xb9, 0x97, 0xd0, 0x5e, 0xcc, 0x91, 0x8d, 0x07, 0x45, 0x48, 0x1c, 0x3d, 0x5d, 0x9a, 0xca, 0xdc, 0x69, 0xe0, 0xc6, 0x0b, 0xf8, 0xf9, 0xf0, 0xd4, 0x86, 0x12, 0x78, 0x58, 0xa2, 0x56, 0xe2, 0x77, 0x8c, 0x9e, 0xf2, 0x93, 0x7e, 0x00, 0xd2, 0x74, 0xc0, }; // ...... void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) { unsigned int i; uint32_t v0=v[0], v1=v[1], delta=0x9E3779B9, sum=delta*num_rounds; for (i=0; i < num_rounds; i++) { v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]); sum -= delta; v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); } v[0]=v0; v[1]=v1; } int main() { uint8_t roundkeys[AES_ROUND_KEY_SIZE]; uint8_t key[16] = {72, 101, 108, 108, 111, 32, 102, 114, 111, 109, 32, 50, 48, 52, 56, 33}; uint8_t data[48] = {174, 171, 207, 246, 74, 249, 129, 3, 174, 132, 149, 48, 57, 153, 218, 1, 53, 119, 54, 231, 124, 65, 77, 67, 239, 176, 170, 155, 1, 39, 33, 156, 2, 225, 14, 103, 194, 189, 254, 194, 163, 151, 234, 239, 101, 237, 139, 65}; uint8_t out[48] = {0}; aes_key_schedule_128(key, roundkeys); for (int i = 0; i < 3; ++i) { aes_decrypt_128(roundkeys, data+16*i, out+16*i); } uint32_t const k[4] = {745567528,745567520,2003788832,1679830126}; for (int i = 0; i < 6; ++i) { uint32_t v[2] = {((uint32_t *) out)[i * 2], ((uint32_t *) out)[i * 2 + 1]}; decipher(32, v, k); printf("0x%08x, 0x%08x, ", v[0], v[1]); } return 0; }
the_shellcode
themida强壳,脱壳后分析(过程略)
注:脚本小子福利:https://github.com/ergrelet/unlicense
对shellcode base64解码后rol 3、xxtea后check
xxtea魔改了MX: z>>6
#include <cstdint> #include <cstdio> #include <string> #define DELTA 0x9e3779b9 #define MX (((z>>6^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z))) void btea(uint32_t *v, int n, uint32_t const key[4]) { uint32_t y, z, sum; unsigned p, rounds, e; if (n > 1) /* Coding Part */ { rounds = 6 + 52/n; sum = 0; z = v[n-1]; do { sum += DELTA; e = (sum >> 2) & 3; for (p=0; p<n-1; p++) { y = v[p+1]; uint32_t tmp = MX; v[p] += tmp; z = v[p]; } y = v[0]; z = v[n-1] += MX; } while (--rounds); } else if (n < -1) /* Decoding Part */ { n = -n; rounds = 6 + 52/n; sum = rounds*DELTA; y = v[0]; do { e = (sum >> 2) & 3; for (p=n-1; p>0; p--) { z = v[p-1]; v[p] -= MX; y = v[p]; } z = v[n-1]; y = v[0] -= MX; sum -= DELTA; } while (--rounds); } } int main() { uint32_t const k1[4] = {'t', 'o', 'r', 'a'}; uint32_t vs[66] = { 0x4B6B89A1, 0x74C15453, 0x4092A06E, 0x429B0C07, 0x40281E84, 0x8B5B44C9, 0x66FEB37B, 0x3C77A603, 0x79C5892D, 0x0D7ADA97, 0x1D51AA56, 0x02D4D703, 0x4FA526BA, 0x32FAD64A, 0x0C0F6091, 0x562B7593, 0xDB9ADD67, 0x76165563, 0xA5F79315, 0x3AEB991D, 0x1AB721D4, 0xAACD9D2C, 0x825C2B27, 0x76A7761A, 0xB4005F18, 0x117F3763, 0x512CC540, 0xC594A16F, 0xD0E24F8C, 0x9CA3E2E9, 0x0A9CC2D5, 0x4629E61D, 0x637129E3, 0xCA4E8AD7, 0xF5DFAF71, 0x474E68AB, 0x542FBC3A, 0xD6741617, 0xAD0DBBE5, 0x62F7BBE3, 0xC8D68C07, 0x880E950E, 0xF80F25BA, 0x767A264C, 0x9A7CE014, 0x5C8BC9EE, 0x5D9EF7D4, 0xB999ACDE, 0xB2EC8E13, 0xEE68232D, 0x927C5FCE, 0xC9E3A85D, 0xAC74B56B, 0x42B6E712, 0xCD2898DA, 0xFCF11C58, 0xF57075EE, 0x5076E678, 0xD4D66A35, 0x95105AB9, 0x1BB04403, 0xB240B959, 0x7B4E261A, 0x23D129D8, 0xF5E752CD, 0x4EA78F70, }; btea(vs, -66, k1); for (int i = 0; i < 33; ++i) { printf("0x%08x, 0x%08x, ", vs[i*2+0], vs[i*2+1]); } return 0; }
rol逆
def ROR(data, shift, size=32): shift %= size body = data >> shift remains = (data << (size - shift)) - (body << size) return (body + remains) value = [0x6243e703, 0x993831bb, 0x925c2396, 0x60925c81, 0x5ca0925c, 0xbd784193, 0xff993152, 0xe1650699, 0x6110e30b, 0x687e0e01, 0x8717c718, 0x925cba92, 0xe1125c80, 0x025c1618, 0x78062cc3, 0x0000f524, 0x82161800, 0x5cc0425c, 0xd61801c2, 0x7800cf1c, 0x00004d24, 0xa15c4a00, 0x9997185c, 0x650699ff, 0x18687e0e, 0xab26d1c7, 0x21e318a7, 0x21e3d920, 0x99ceab60, 0x1c4e99ff, 0xb5788216, 0x7e0e5020, 0x0ac71868, 0xab70cf1c, 0x687e0e8f, 0x99ff99ba, 0x21a25c4e, 0xb57892e1, 0x3bc570e0, 0xbf333333, 0x5cd78e5f, 0xf8470e16, 0x206c1618, 0xd2c65904, 0x5020b578, 0x7e0e1e59, 0x0ac71868, 0xab70cf1c, 0x687e0ea6, 0xa321e1d9, 0x9b2943b0, 0x265c0000, 0x007b7343, 0x5c82a200, 0xff4221e2, 0x43a05f9e, 0x00009b29, 0xcb43265c, 0xa2009b2b, 0x21e25c82, 0xc29eff42, 0xc2c2c2c2, 0xc2c2c2c2, 0xfac21e0b, 0x4f905cd2, 0xffffff58,] data = struct.pack("<66L", *value) data = bytearray([ROR(i, 3, 8) for i in data]) shellcode = base64.b64encode(data).decode() print(shellcode)
check flag用了ror13 hash
def ror13(target): # return ((target << 0x13) & 0xfff80000) | ((target >> 0xd) & 0x07ffff) return ((target << 0x13) & 0xffffffff) | ((target >> 0xd) & 0x07ffff) def calc(s): target = 0 for c in s: target = ror13(target) target += c return target
带壳调试,反壳带的anti-debug后,拿到需要的参数,简单逆过程
import hashlib msd = b'LoadLibraryExA' data = bytearray(b''.fromhex("69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E")) for i in range(14): data[i] += msd[i] % 5 base = b"YPxoTHcmBzPSZItSMItSDItSFItyKA+3SiYz/zPArDxhfAIsIMHPDQP44vBSV4tSEItCPAPCi0B4hcAPhL4AAAADwlCLSBiLWCAD2oP5AA+EqQAAAEmLNIsD8jP/M8Cswc8NA/g6xHX0A3wkBDt8JAx12TP/M8mDwlAPtgQKwc8NA/hBg/kOdfHBzw1XM/8zyYtUJDxSD7YcDrhnZmZm9+vR+ovCwegfA8KNBIAr2FoPtgQKK8PBzw0D+EGD+Q511MHPDTs8JHQWaCVzAACLxGhubwAAVFCLXCRI/9PrFGglcwAAi8RoeWVzAFRQi1wkSP/TWFhYWFhYWFhYYcNYX1qLEukL////" base += data print(hashlib.md5(base).hexdigest())
发表回复