总共三题逆向,2题VM,1题LLVM FLA
之前一直没机会去做VM类型的题目(其实是我懒),这次做到了,算是练手了。题目也比较适合入门。
badPDF
右键属性提取出shell
%SystemRoot%\system32\cmd.exe /c copy "20200308-sitrep-48-covid-19.pdf.lnk" %tmp%\\g4ZokyumBB2gDn.tmp /y&for /r C:\\Windows\\System32\\ %i in (*ertu*.exe) do copy %i %tmp%\\msoia.exe /y&findstr.exe "TVNDRgAAAA" %tmp%\\g4ZokyumBB2gDn.tmp>%tmp%\\cSi1r0uywDNvDu.
运行ink,看到%tmp%
目录下释放的一些文件
<?xml version='1.0'?> <stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt" xmlns:user="placeholder" version="1.0"> <output method="text"/> <ms:script implements-prefix="user" language="VBScript"> <![CDATA[ rBOH7OLTCVxzkH=HrtvBsRh3gNUbe("676d60667a64333665326564333665326564333665326536653265643336656564333665327c"):execute(rBOH7OLTCVxzkH):function HrtvBsRh3gNUbe(bhhz6HalbOkrki):for rBOH7OLTCVxzkH=1 to len(bhhz6HalbOkrki)step 2:HrtvBsRh3gNUbe=HrtvBsRh3gNUbe&chr(asc(chr("&h"&mid(bhhz6HalbOkrki,rBOH7OLTCVxzkH,2)))xor 1):next:end function: ]]> </ms:script> </stylesheet>
简单异或
babyrsa
factordb分解e
import gmpy2 from Crypto.Util.number import bytes_to_long, long_to_bytes N = 13123058934861171416713230498081453101147538789122070079961388806126697916963123413431108069961369055630747412550900239402710827847917960870358653962948282381351741121884528399369764530446509936240262290248305226552117100584726616255292963971141510518678552679033220315246377746270515853987903184512948801397452104554589803725619076066339968999308910127885089547678968793196148780382182445270838659078189316664538631875879022325427220682805580410213245364855569367702919157881367085677283124732874621569379901272662162025780608669577546548333274766058755786449491277002349918598971841605936268030140638579388226573929 c = 1492164290534197296766878830710549288168716657792979479408332026408553210558539364503279432780006256047888761718878241924947937039103166564146378209168719163067531460700424309878383312837345239570897122826051628153030129647363574035072755426112229160684859510640271933580581310029921376842631120847546030843821787623965614564745724229763999106839802052036834811357341644073138100679508864747009014415530176077648226083725813290110828240582884113726976794751006967153951269748482024859714451264220728184903144004573228365893961477199925864862018084224563883101101842275596219857205470076943493098825250412323522013524 p = 98197216341757567488149177586991336976901080454854408243068885480633972200382596026756300968618883148721598031574296054706280190113587145906781375704611841087782526897314537785060868780928063942914187241017272444601926795083433477673935377466676026146695321415853502288291409333200661670651818749836420808033 q = 133639826298015917901017908376475546339925646165363264658181838203059432536492968144231040597990919971381628901127402671873954769629458944972912180415794436700950304720548263026421362847590283353425105178540468631051824814390421486132775876582962969734956410033443729557703719598998956317920674659744121941513 phi = (q - 1) * (p - 1) d = gmpy2.invert(e, phi) m = gmpy2.powmod(c, d, N) m = long_to_bytes(m) print(m)
EasyVM
小型VM
魔改Base64,魔改点:
v4[v6 - 4] = aAbcdefghijklmn[v8 >> 2] ^ 0xA; v4[v6 - 3] = aAbcdefghijklmn[(*((unsigned __int8 *)v7 - 3) >> 4) | (16 * (*(v7 - 4) & 3))] ^ 0xB; v4[v6 - 2] = aAbcdefghijklmn[(*((unsigned __int8 *)v7 - 2) >> 6) | (4 * (*(v7 - 3) & 0xF))] ^ 0xC; v4[v6 - 1] = aAbcdefghijklmn[*(v7 - 2) & 0x3F] ^ 0xD;
而后分析VM
结构体
struct vm { void* vm; _BYTE* opcode; _DWORD eax; _DWORD ebx; _DWORD ecx; _DWORD edx; _BYTE* uncode; _DWORD vla; _BYTE* flag; }
写parser
vmcode = [0xCA, 0x00, 0x00, 0x00, 0x00, 0xCB, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCF, 0xC9, 0xEE, 0x00, 0x00, 0x00, 0xCF, 0xD1, 0xD3, 0x01, 0xFE, 0xC2, 0xD2, 0x39, 0x00, 0x00, 0x00, 0xD4, 0xEC, 0xFF] func = ["scheduler", {"name": "inc_eax", "step": 1}, {"name": "inc_ebx", "step": 1}, {"name": "inc_ecx", "step": 1}, {"name": "mov_eax_ebx", "step": 1}, {"name": "mov_eax_ecx", "step": 1}, {"name": "mov_ebx_eax", "step": 1}, {"name": "mov_ebx_ecx", "step": 1}, {"name": "mov_ecx_eax", "step": 1}, {"name": "mov_ecx_ebx", "step": 1}, {"name": "mov_eax_data", "step": 5}, {"name": "mov_ebx_data", "step": 5}, {"name": "mov_ecx_data", "step": 5}, {"name": "mov_eax_flag", "step": 1}, {"name": "mov_ebx_flag", "step": 1}, {"name": "xor_eax_ebx", "step": 1}, {"name": "xor_ebx_eax", "step": 1}, {"name": "cmp_eax_uncode", "step": 1}, {"name": "cmp_ebx_uncode", "step": 1}, {"name": "cmp_ecx_data", "step": 5}, {"name": "sub_4015D0", "step": 3}, {"name": "sub_4015F0", "step": 3}, ] def findit(): rt = [192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 0xfe, 0xff] ip = 0 while ip < len(vmcode): idx = rt.index(vmcode[ip]) + 1 if func[idx]["step"] == 5: print(func[idx]["name"], hex(int.from_bytes(vmcode[ip+1:ip+5], byteorder="little"))) else: print(func[idx]["name"]) ip += func[idx]["step"] findit() """ ebx = 0x0 ecx = 0x0 loop: eax = flag[ecx] ebx ^= eax eax = 0xee ebx ^= eax uncode[ecx] == ebx ecx++ jmp loop; """
逆运算
# -*- coding:utf-8 -*- """ @Author: Mas0n @File: hws1.py @Time: 2022-01-23 15:10 @Desc: It's all about getting better. """ from base64 import b64decode def dec(strs): lt = bytearray(strs.encode()) for i in range(0, len(lt), 4): lt[i] ^= 0xa lt[i + 1] ^= 0xb lt[i + 2] ^= 0xc lt[i + 3] ^= 0xd return b64decode(lt) code = bytearray([0xBE, 0x36, 0xAC, 0x27, 0x99, 0x4F, 0xDE, 0x44, 0xEE, 0x5F, 0xDA, 0x0B, 0xB5, 0x17, 0xB8, 0x68, 0xC2, 0x4E, 0x9C, 0x4A, 0xE1, 0x43, 0xF0, 0x22, 0x8A, 0x3B, 0x88, 0x5B, 0xE5, 0x54, 0xFF, 0x68, 0xD5, 0x67, 0xD4, 0x06, 0xAD, 0x0B, 0xD8, 0x50, 0xF9, 0x58, 0xE0, 0x6F, 0xC5, 0x4A, 0xFD, 0x2F, 0x84, 0x36, 0x85, 0x52, 0xFB, 0x73, 0xD7, 0x0D, 0xE3, 0x00, 0x00, 0x00]) for i in range(len(code) - 1 - 2, -1, -1): code[i] ^= 0xee if i > 0: code[i] ^= code[i - 1] print(dec(code.decode()))
babyre
llvm控制流混淆
patch掉花指令
比较明显的换表Base64
指令不是特别多,调试确定执行流程
大致如下
Src = sub_4221F0(dword_452E50); memmove(data, Src, 0x20u); for (int i = 0; i < 8; i++) { v6 = ~*(_DWORD *)&data[4 * v33]; v7 = v6 & v34; v34 = v6 & v34 | ~v34 & *(_DWORD *)&data[4 * v33]; } for (int i = 0; i < 8; i++) { v9 = ~*(_DWORD *)&data[4 * v32]; *(_DWORD *)&data[4 * v32] = v9 & v34 | ~v34 & *(_DWORD *)&data[4 * v32]; } for (int i = 0; i < 33; i+=3) { ··· // 换表Base64 for (int v23 = i; v23 < 33; v23+=3) { data[v23] = (v27 & 0xF4 | ~v27 & 0xB) ^ (data[v23] & 0xF4 | ~data[v23] & 0xB); data[v23 + 1] = ~v26 & data[v23 + 1] | ~data[v23 + 1] & v26; data[v23 + 2] = ~v25 & data[v23 + 2] | ~data[v23 + 2] & v25; }
综上,z3求解
# -*- coding:utf-8 -*- """ @Author: Mas0n @File: hws3.py @Time: 2022-01-23 17:45 @Desc: It's all about getting better. """ from z3 import * import base64 def z3enc(inputs): data = inputs.copy() i = 0 for _ in range((len(data) - 1) % 3): data.append(0) while 1: chr1 = (data[i]) i += 1 chr2 = (data[i]) i += 1 chr3 = (data[i]) i += 1 enc1 = chr1 >> 2 enc2 = ((chr1 & 3) << 4) | (chr2 >> 4) enc3 = ((chr2 & 15) << 2) | (chr3 >> 6) for j in range(i, len(data), 3): data[j] = (enc1 & 0xF4 | ~enc1 & 0xB) ^ (data[j] & 0xF4 | ~data[j] & 0xB) data[j + 1] = ~enc2 & data[j + 1] | ~data[j + 1] & enc2 data[j + 2] = ~enc3 & data[j + 2] | ~data[j + 2] & enc3 if i >= len(data): break return data baseMaps = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" newMaps = "QVEJAfHmUYjBac+u8Ph5n9Od16FrICL/X0GvtM4qk7T2z3wNSsyoebilxWKgZpRD=" cipherText = "Fi9X/fxX6Q6JBfUfBM1V/y6V6PcPjMaQLl9IuttFuH68" cipherText = cipherText.translate(cipherText.maketrans(newMaps, baseMaps)) bingo = base64.b64decode(cipherText.encode('utf-8')) # Step 1 sol = Solver() flag = [BitVec(f"flag[{i}]", 8) for i in range(32)] res = z3enc(flag) for i in range(32): sol.add(res[i] == bingo[i]) assert sol.check() == sat mol = sol.model() # print(mol) end = bytearray([mol.eval(i).as_long() for i in flag]) print(end) # Step 2 ended = [int.from_bytes(end[4*i:4*i+4], byteorder="little") for i in range(8)] sol = Solver() flag = [BitVec(f"flag[{i}]", 32) for i in range(8)] tmps = flag.copy() v32 = 0 for i in range(8): v6 = ~tmps[i] v7 = v6 & v32 v32 = v6 & v32 | ~v32 & tmps[i] for i in range(8): tmps[i] = ~tmps[i] & v32 | ~v32 & tmps[i] for i in range(8): sol.add(ended[i] == tmps[i]) assert sol.check() == sat mol = sol.model() # print(mol) print("".join([int.to_bytes(mol.eval(i).as_long(), byteorder="little", length=4).decode() for i in flag]))
做完找llvm资料的时候直呼:脚本小子真香!
moliam/llvm-fla-cracker: cracker for the llvm-fla-obfuscator (github.com)
BabyVM
还是VM
patch花指令
from ida_bytes import get_bytes, patch_bytes import re addr = 0x00412CC0 end = 0x00413991 buf = get_bytes(addr, end-addr) buf = buf.replace(b"\x74\x03\x75\x01\xE8", b"\x90"*5) patch_bytes(addr, buf)
初始化函数sub_292BB0
void sub_292BB0() { __CheckForDebuggerJustMyCode(&unk_2A1002); stack = malloc(0x8000u); memory = malloc(0x800000u); j_memset(®, 0, sizeof(reg)); j_memset(flags, 0, sizeof(flags)); LODWORD(reg.R[4]) = 256; HIDWORD(reg.R[4]) = 0; vmrun((int)vm0); vmrun((int)vm1); }
执行函数sub_292CC0
寄存器结构
struct regs { _QWORD R0; _QWORD R1; _QWORD R2; _QWORD R3; _QWORD R4; _QWORD R5; _QWORD R6; _QWORD R7; _QWORD R8; _QWORD R9; _QWORD R10; _QWORD R11; _QWORD R12; _QWORD R13; _QWORD R14; _QWORD RIP; }
VM结构
struct vm { _DWORD opcode; _QWORD num; _QWORD right; }
分析指令
parser
maps = { 0x0: "mov Memory[R[{num}]], {right}", 0x1: "mov R[{num}], {right}", 0x2: "mov R[{num}], R[{right}]", 0x3: "mov R[{num}], Memory[R[{right}]]", 0x4: "mov Memory[R[{num}]], R[{right}]", 0x5: "push R[{num}]", 0x6: "pop R[{num}]", 0x7: "add R[{num}], {right}", 0x8: "add R[{num}], R[{right}]", 0x9: "dec R[{num}], {right}", 0xa: "dec R[{num}], R[{right}]", 0xb: "mul R[{num}], {right}", 0xc: "mul R[{num}], R[{right}]", 0xd: "shl R[{num}], {right}", 0xe: "shl R[{num}], R[{right}]", 0xf: "shr R[{num}], {right}", 0x10: "shr R[{num}], R[{right}]", 0x11: "xor R[{num}], {right}", 0x12: "xor R[{num}], R[{right}]", 0x13: "or R[{num}], {right}", 0x14: "or R[{num}], R[{right}]", 0x15: "and R[{num}], {right}", 0x16: "and R[{num}], R[{right}]", 0x17: "getchar R[{num}]", 0x18: "putchar R[{num}]", 0x19: "exit", 0x1a: "cmp R[{num}], {right}", 0x1b: "cmp R[{num}], R[{right}]", 0x1c: "je {num}", 0x1d: "jmp {num}", 0x1e: "jb {num}", 0x1f: "jne {num}", } _hex = lambda _d: hex(_d) if _d > 0x9 else _d class VM: def __init__(self, opcode, regnum, right): self.opcode = opcode self.regnum = regnum self.right = right def __str__(self): return ' '.join(['%s:0x%x' % item for item in self.__dict__.items()]) def to_code(self): try: return maps[self.opcode].format(num=_hex(self.regnum), right=_hex(self.right)) except KeyError: return "(error):" + self.__str__() def parse(code: list): starr = [] for _i in range(0, len(code), 3): vm = VM(code[_i + 0], code[_i + 1], code[_i + 2]) starr.append(vm) for _i, v in enumerate(starr): print(_hex(_i), ":", v.to_code())
共计四组数据
加载了比对数据
0 : xor R[2], R[2] 1 : mov Memory[R[2]], 0xff 2 : add R[2], 1 3 : mov Memory[R[2]], 0x223 4 : add R[2], 1 5 : mov Memory[R[2]], 0x23b 6 : add R[2], 1 7 : mov Memory[R[2]], 0x237 8 : add R[2], 1 9 : mov Memory[R[2]], 0x237 0xa : add R[2], 1 0xb : mov Memory[R[2]], 0x24b 0xc : add R[2], 1 0xd : mov Memory[R[2]], 0x22b 0xe : add R[2], 1 0xf : mov Memory[R[2]], 0xfb 0x10 : add R[2], 1 0x11 : mov Memory[R[2]], 0x22b 0x12 : add R[2], 1 0x13 : mov Memory[R[2]], 0x223 0x14 : add R[2], 1 0x15 : mov Memory[R[2]], 0x24f 0x16 : add R[2], 1 0x17 : mov Memory[R[2]], 0xef 0x18 : add R[2], 1 0x19 : mov Memory[R[2]], 0x237 0x1a : add R[2], 1 0x1b : mov Memory[R[2]], 0xef 0x1c : add R[2], 1 0x1d : mov Memory[R[2]], 0x24f 0x1e : add R[2], 1 0x1f : mov Memory[R[2]], 0x24f 0x20 : add R[2], 1 0x21 : mov Memory[R[2]], 0x223 0x22 : add R[2], 1 0x23 : mov Memory[R[2]], 0x223 0x24 : add R[2], 1 0x25 : mov Memory[R[2]], 0x23b 0x26 : add R[2], 1 0x27 : mov Memory[R[2]], 0x237 0x28 : add R[2], 1 0x29 : mov Memory[R[2]], 0xff 0x2a : add R[2], 1 0x2b : mov Memory[R[2]], 0x233 0x2c : add R[2], 1 0x2d : mov Memory[R[2]], 0x233 0x2e : add R[2], 1 0x2f : mov Memory[R[2]], 0x233 0x30 : add R[2], 1 0x31 : mov Memory[R[2]], 0x237 0x32 : add R[2], 1 0x33 : mov Memory[R[2]], 0x24b 0x34 : add R[2], 1 0x35 : mov Memory[R[2]], 0x233 0x36 : add R[2], 1 0x37 : mov Memory[R[2]], 0x24f 0x38 : add R[2], 1 0x39 : mov Memory[R[2]], 0x22b 0x3a : add R[2], 1 0x3b : mov Memory[R[2]], 0x22b 0x3c : add R[2], 1 0x3d : mov Memory[R[2]], 0x24b 0x3e : add R[2], 1 0x3f : mov Memory[R[2]], 0xef 0x40 : add R[2], 1
比对数据循环自减0x63
0 : xor R[2], R[2] 1 : mov R[0], Memory[R[2]] 2 : dec R[0], 0x63 3 : mov Memory[R[2]], R[0] 4 : add R[2], 1 5 : cmp R[2], 0x20 6 : jb 1 7 : exit
获取输入文本,check输入长度0x26
0 : xor R[0], R[0] 1 : xor R[1], R[1] 2 : xor R[2], R[2] 3 : xor R[3], R[3] 4 : xor R[6], R[6] 5 : xor R[7], R[7] 6 : mov R[0], 0x69 7 : mov R[1], 0x6e 8 : mov R[2], 0x70 9 : mov R[3], 0x75 0xa : mov R[6], 0x74 0xb : mov R[7], 0x20 0xc : putchar R[0] 0xd : putchar R[1] 0xe : putchar R[2] 0xf : putchar R[3] 0x10 : putchar R[6] 0x11 : putchar R[7] 0x12 : mov R[0], 0x66 0x13 : mov R[1], 0x6c 0x14 : mov R[2], 0x61 0x15 : mov R[3], 0x67 0x16 : mov R[6], 0x3a 0x17 : mov R[7], 0x20 0x18 : putchar R[0] 0x19 : putchar R[1] 0x1a : putchar R[2] 0x1b : putchar R[3] 0x1c : putchar R[6] 0x1d : putchar R[7] 0x1e : xor R[1], R[1] 0x1f : getchar R[0] 0x20 : push R[0] 0x21 : add R[1], 1 0x22 : cmp R[1], 0x26 0x23 : jb 0x1f 0x24 : exit
- 与0x42异或
- 左移2位
与比对数据比对
0 : pop R[0] 1 : cmp R[0], 0x7d 2 : je 0x12 3 : mov R[0], 0x77 4 : mov R[1], 0x72 5 : mov R[2], 0x6f 6 : mov R[3], 0x6e 7 : mov R[6], 0x67 8 : mov R[7], 0x21 9 : putchar R[0] 0xa : putchar R[1] 0xb : putchar R[2] 0xc : putchar R[3] 0xd : putchar R[6] 0xe : putchar R[7] 0xf : mov R[0], 0xa 0x10 : putchar R[0] 0x11 : exit 0x12 : mov R[8], 0x100 0x13 : cmp R[8], 0xe1 0x14 : jb 0x19 0x15 : pop R[0] 0x16 : mov Memory[R[8]], R[0] 0x17 : dec R[8], 1 0x18 : jmp 0x13 0x19 : pop R[0] 0x1a : cmp R[0], 0x7b 0x1b : jne 3 0x1c : pop R[0] 0x1d : cmp R[0], 0x67 0x1e : jne 3 0x1f : pop R[0] 0x20 : cmp R[0], 0x61 0x21 : jne 3 0x22 : pop R[0] 0x23 : cmp R[0], 0x6c 0x24 : jne 3 0x25 : pop R[0] 0x26 : cmp R[0], 0x66 0x27 : jne 3 0x28 : xor R[9], R[9] 0x29 : mov R[0xa], 0xe1 0x2a : mov R[7], Memory[R[9]] 0x2b : mov R[6], Memory[R[0xa]] 0x2c : xor R[6], 0x42 0x2d : shl R[6], 2 0x2e : cmp R[6], R[7] 0x2f : jne 3 0x30 : add R[9], 1 0x31 : add R[0xa], 1 0x32 : cmp R[9], 0x20 0x33 : jb 0x2a 0x34 : mov R[0], 0x63 0x35 : mov R[1], 0x6f 0x36 : mov R[2], 0x72 0x37 : mov R[3], 0x72 0x38 : mov R[6], 0x65 0x39 : mov R[7], 0x63 0x3a : putchar R[0] 0x3b : putchar R[1] 0x3c : putchar R[2] 0x3d : putchar R[3] 0x3e : putchar R[6] 0x3f : putchar R[7]
逆过程
enc = [0xff, 0x223, 0x23b, 0x237, 0x237, 0x24b, 0x22b, 0xfb, 0x22b, 0x223, 0x24f, 0xef, 0x237, 0xef, 0x24f, 0x24f, 0x223, 0x223, 0x23b, 0x237, 0xff, 0x233, 0x233, 0x233, 0x237, 0x24b, 0x233, 0x24f, 0x22b, 0x22b, 0x24b, 0xef] for i in range(0x20): enc[i] -= 0x63 for i in range(0x20): enc[i] = enc[i] >> 2 enc[i] = enc[i] ^ 0x42 print(bytearray(enc))
发表回复