yulian's blog - reverse https://dirtycow.cn/tag/reverse/ 2025羊城杯初赛Reverse-PLUS详细wp https://dirtycow.cn/393.html 2025-10-16T01:57:00+08:00 思路init.pyd模块分析image-20251015234327845.png查看代码,里面有一堆加法,然后传入了init中的方法int()、exit()、exec、m()方法先对python代码进行简单的简化查看一下init.pyd中的方法pyd_info.py:import init x = dir(init) print("fun b: " ,init.b) print("fun c: " , init.c) print("fun e: " , init.e) print("fun exec: " , init.exec) print("fun exit: " , init.exit) print("fun int: " , init.int) print("fun m: " , init.m) print("fun p: " , init.p) help(init) #result: ''' fun b: <function b64encode at 0x0000000001671F70> fun c: <class 'unicorn.unicorn_py3.unicorn.Uc'> fun e: <unicorn.unicorn_py3.arch.intel.UcIntel object at 0x0000000001522F10> fun exec: <cyfunction exec at 0x000000000147F5F0> fun exit: <built-in function eval> fun int: <class 'str'> fun m: <class 'operator.methodcaller'> fun p: <built-in function print> Help on module init: NAME init FUNCTIONS a2b_hex(hexstr, /) Binary data of hexadecimal representation. hexstr must contain an even number of hex digits (upper or lower case). This function is also available as "unhexlify()". exec(x) exit = eval(source, globals=None, locals=None, /) Evaluate the given source in the context of globals and locals. The source may be a string representing a Python expression or a code object as returned by compile(). The globals must be a dictionary and locals can be any mapping, defaulting to the current globals and locals. If only globals is given, locals defaults to it. i = input(prompt=None, /) Read a string from standard input. The trailing newline is stripped. The prompt string, if given, is printed to standard output without a trailing newline before reading input. If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError. On *nix systems, readline is used if available. p = print(...) print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False) Prints the values to a stream, or to sys.stdout by default. Optional keyword arguments: file: a file-like object (stream); defaults to the current sys.stdout. sep: string inserted between values, default a space. end: string appended after the last value, default a newline. flush: whether to forcibly flush the stream. DATA __test__ = {} e = <unicorn.unicorn_py3.arch.intel.UcIntel object> FILE c:\users\36134\desktop\2025羊城杯\re\re2\chal\init.pyd */ '''从help中可以看出b = b64encode() p = print(...) i = input(prompt=None, /) exit = eval()e = <unicorn.unicorn_py3.arch.intel.UcIntel object>m = operator.methodcaller()init.int()函数是str类型了,尝试调用这个函数image-20251016001416411.png这个函数实现了加法,返回str类型的和init.exec()函数暂时看不出来,先放着,根据从init.pyc中得知的信息,将脚本简化处理plus.py处理脚本:import re with open("plus.py", "r") as f: data = f.read() matches = re.findall(r'int\((.*?)\)', data) solve = [] for i in matches: if i == '': solve.append('') else: solve.append(eval(i)) for i, match in enumerate(matches): data = data.replace(f'int({match})', f"'{solve[i]}'") solve2 = [] matches = re.findall(r'exit\((.*?)\)', data) for i in matches: solve2.append(eval(i)) for i, match in enumerate(matches): data = data.replace(f'exit({match})', f"{solve2[i]}") data = data.replace(';','\n') print(data) 处理之后代码:from init import * m(exec(30792292888306032),16777216,2097152)(e) m(exec(30792292888306032),18874368,65536)(e) m(exec(2018003706771258569829),16777216,exec(2154308209104587365050518702243508477825638429417674506632669006169365944097218288620502508770072595029515733547630393909115142517795439449349606840082096284733042186109675198923974401239556369486310477745337218358380860128987662749468317325542233718690074933730651941880380559453),)(e) m(exec(2110235738289946063973),44,18939903)(e) m(exec(2018003706771258569829),18878464, i(exec(520485229507545392928716380743873332979750615584)).encode())(e) m(exec(2110235738289946063973),39,18878464)(e) m(exec(2110235738289946063973),43,44)(e) m(exec(2110235738289946063973),40,7)(e) m(exec(1871008466716552426100), 16777216, 16777332)(e) p(exec(1735356260)) if (b(m(exec(7882826979490488676), 18878464, 44)(e)).decode()== exec(636496797464929889819018589958474261894226380884858896837050849823120096559828809884712107801783610237788137002972622711849132377866432975817021)) else p(exec(31084432670685473)) #type:ignore分析e();m();init.exec查看处理之后的代码,有一个很大的int数值传入了init.exec(),调用这个函数查看image-20251016004049822.png这个函数实现了int2str的功能自己实现方法:def int2bytes(n, byteorder: str = "big"): if n == 0: return b"\x00" length = (n.bit_length() + 7) // 8 return n.to_bytes(length, byteorder)接下来分析m() e()方法m()方法是operator.methodcaller(),这个方法用来创建函数,类似于回调函数m(x1, x2, x3)(e)等价于e.x1(x2,x3)e()方法是unicorn.unicorn_py3.arch.intel.UcIntelUnicorn 是一个基于 QEMU 的CPU 模拟器框架可以将上面e写成e = unicorn.Uc(UC_ARCH_X86, UC_MODE_64),第一个参数是cpu架构,第二个参数是模式还原代码根据上面的分析,就可以将plus.py还原成原本的代码from unicorn import * from unicorn.x86_const import * from operator import methodcaller from base64 import b64encode as b e = Uc(UC_ARCH_X86, UC_MODE_64) e.mem_map(16777216,2097152) e.mem_map(18874368,65536) #写入汇编指令 e.mem_write(16777216,b'\xf3\x0f\x1e\xfaUH\x89\xe5H\x89}\xe8\x89u\xe4\x89\xd0\x88E\xe0\xc7E\xfc\x00\x00\x00\x00\xebL\x8bU\xfcH\x8bE\xe8H\x01\xd0\x0f\xb6\x00\x8d\x0c\xc5\x00\x00\x00\x00\x8bU\xfcH\x8bE\xe8H\x01\xd0\x0f\xb6\x002E\xe0\x8d4\x01\x8bU\xfcH\x8bE\xe8H\x01\xd0\x0f\xb6\x00\xc1\xe0\x05\x89\xc1\x8bU\xfcH\x8bE\xe8H\x01\xd0\x8d\x14\x0e\x88\x10\x83E\xfc\x01\x8bE\xfc;E\xe4r\xac\x90\x90]') e.reg_write(44,18939903) e.mem_write(18878464,input("[+]input your flag: ").encode()) e.reg_write(39,18878464) e.reg_write(43,44) e.reg_write(40,7) e.emu_start(16777216,16777332) print("good") if ( b(e.mem_read(18878464,44)).decode() == "425MvHMxtLqZ3ty3RZkw3mwwulNRjkswbpkDMK+3CDCOtbe6kzAqPyrcEAI=" ) else print("no way!") 逐行解析e = Uc(UC_ARCH_X86, UC_MODE_64)创建一个 x86-64 的 Unicorn 模拟器实例e.mem_map(16777216,2097152)在地址 0x01000000(十进制 16777216)映射 2MB 内存,作为放置并执行 shellcode 的区域e.mem_map(18874368,65536)在地址 0x01200000(十进制 18874368)映射 64KB 内存,作为数据区e.mem_write(16777216, b'\xf3\x0f\x1e\xfa...')把一段机器码(长度 116 bytes)写到 0x01000000e.reg_write(44,18939903)给某个寄存器写入常数 18939903 。代码里并没有以名字注明是哪个寄存器,但其作用是给 shellcode 一个初始化值e.mem_write(18878464,input("[+]input your flag: ").encode())把用户的输入写到地址 18878464 这个地址和上面 data 区的基址有关系:18878464 - 18874368 = 4096 = 0x1000所以输入被写入 data 区内偏移 0x1000 的位置(也就是 0x01201000)三个 reg_write:e.reg_write(39,18878464) e.reg_write(43,44) e.reg_write(40,7)这三行把函数参数或工作寄存器设为:一个指针(指向你放入的输入:18878464)一个长度 / 计数(44)另一个常数(7)在 x86-64 的调用约定里,整数参数通常通过 RDI/RSI/RDX/RCX/… 传递 这里使用具体的寄存器编号来配合 shellcode 读取参数e.emu_start(16777216,16777332)开始在 0x01000000 执行,直到 0x01000000 + 116,执行过程中,shellcode 会读取/写入 data 区最后比较:b(e.mem_read(18878464,44)).decode() == "425MvHMxtLqZ3ty3RZkw3mwwulNRjkswbpkDMK+3CDCOtbe6kzAqPyrcEAI="先对处理后的 44 字节用 base64编码得到字符串,再和enc进行比较汇编分析image-20251016014646900.png将汇编指令以二进制保存,使用ida打开分析,稍微处理一下数据类型和变量名image-20251016014839854.png这里使用异或和乘法进行运算,因为除法不能直接逆运算,所以要爆破Exp写脚本爆破flagimport base64 enc = base64.b64decode("425MvHMxtLqZ3ty3RZkw3mwwulNRjkswbpkDMK+3CDCOtbe6kzAqPyrcEAI=") flag = '' for i in range(44): for j in range(32,127): if ((8 * j) + (7 ^ j) + (32 * j)) &0xff == enc[i]: flag += chr(j) break print(flag) #result #DASCTF{un1c0rn_1s_u4fal_And_h0w_ab0ut_exec?} 第七届浙江省大学生网络与信息安全竞赛决赛reverse-wp https://dirtycow.cn/269.html 2024-11-09T17:51:00+08:00 Reverse1思路:64位elfimage-20241110155524669.pngida分析image-20241110160145828.png分析这几个函数init函数初始化了一个table,一看就是rc4加密image-20241110160217367.png继续看crypt1 和 crypt2, 是魔改的rc4image-20241110160408630.pngbefore_main函数加密key,秘钥是keykeyimage-20241110162211876.pngafter_main函数使用加密之后的key作为秘钥加密了flagimage-20241110162622396.pngexp:def crypt1(s,key, key_len): v5 = 0 v6 = 0 res = [] for i in range(key_len): v5 = (v5 + 1) % 256 v6 = (v6 + s[v5]) % 256 v4 = s[v5] s[v5] = s[v6] s[v6] = v4 res.append(key[i] ^ (s[(s[v5] + s[v6]) %256])) return res def crypt2(s,enc,enc_len): v5 = 0 v6 = 0 res = [] for i in range(enc_len): v5 = (v5 + 1) % 256 v6 = (v6 + s[v5]) % 256 v4 = s[v5] s[v5] = s[v6] s[v6] = v4 res.append(enc[i] + s[(s[v5] + s[v6])%256]) return res def init(s,key,key_len): v8 = [0]*258 for i in range(256): s[i] = i v8[i] = key[i % key_len] v6 =0 for j in range(256): v6 = (v8[j] + v6 + s[j]) % 256 v4 = s[j] s[j] = s[v6] s[v6] = v4 s = [0]*256 key1 = [ord(b) for b in "keykey"] key = [ord(b) for b in "ban_debug!"] init(s,key1,len(key1)) res = crypt1(s,key,len(key)) print(res) s2 = [0]*256 key2 = init(s2, res,len(res)) enc = [0x4E, 0x47, 0x38, 0x47, 0x62, 0x0A, 0x79, 0x6A, 0x03, 0x66, 0xC0, 0x69, 0x8D, 0x1C, 0x84, 0x0F, 0x54, 0x4A, 0x3B, 0x08, 0xE3, 0x30, 0x4F, 0xB9, 0x6C, 0xAB, 0x36, 0x24, 0x52, 0x81, 0xCF] flag = crypt2(s2,enc,len(enc)) for i in flag: print(chr(i%256),end="") ''' 运行结果 [105, 13, 90, 178, 64, 234, 25, 63, 47, 106] flag{1237-12938-9372-1923-4u92} ''' reverse2思路:有upx, 十六进制查看upx特征是否被修改image-20241110164828280.png将这三个ABC改回成UPX就能脱壳image-20241110164949354.pngida分析代码main函数中看到一个密文image-20241110165204829.png往下看 很明显的base64加密,查看a9876543210zyxw数组image-20241110165249211.png是base64换表image-20241110165347969.pngexp:赛博厨子直接一把梭image-20241110165557240.png 青少年ctf Reverse mfc https://dirtycow.cn/198.html 2023-12-20T21:26:00+08:00 思路:拿到题目先查壳image-20231220211157807.png是windows 64为的程序 双击打开,随便输如测试image-20231220211517370.png根据题目名字,推测这是使用mfc框架开发的直接上ida在import中搜索messagebox跟到调用这个函数的地方发现了验证flag的地方v7中存的是加密的flag ^0x87 就能还原flag image-20231220212121416.png直接上脚本exp:encode = [0xE0E6EBE1, 0x0E3E1B6FC, 0x0BEB7B6B2, 0x0B2B1BEE2, 0x0E2B6B6B2, 0x0B3B0B3E2, 0x0E3E3B2E2,0x0B7B7B3E2,0x0B6B0E6B0,0x0FAE1 ] for i in encode: tmp = i.to_bytes(4,'little') for j in tmp: print(chr(j^0x87), end="")flag:flag{1fd5109e965511ee474e5dde4007a71f} 2023楚慧杯初赛reverse部分WriteUp https://dirtycow.cn/186.html 2023-12-19T15:35:00+08:00 babyre思路:提示是xxtea加密image-20231219142425780.png用ida打开,找到了key和加密后的data值image-20231219142609263.png跟进去encode函数查看 发现这并不是xxtea加密,而是xtea加密,比赛的时候一直在用xxtea的脚本解,没解出来image-20231219142741402.png接下来提取key和encode_data将qword_400E80和qword_400E88拆成4个dword数据就是key即int key[] = {0xDEADBEEF,87654321,0xFACEB00C,0xCAFEBABE};将encode_data也按照上述的数据类型提取int data[] = {0x168F8672,0x2DBD824,0x0CF647FCA,0x0E6EFA7EF,0x4AE016F0,0x0C5832E1D,0x455C0A05,0x0FFEB8140,0x0BE9561EF,0x7F819E23,0x3BC04269,0x0C68B825B,0x0E6A5B1F0,0x0BD03CBBD,0x0A9B3CE0E,0x6C85E6E7,0x9F5C71EF,0x3BE4BD57};image-20231219143124477.png直接拿脚本解密exp#include <stdio.h> #include <stdint.h> /* take 64 bits of data in v[0] and v[1] and 128 bits of key[0] - key[3] */ void encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) { unsigned int i; uint32_t v0=v[0], v1=v[1], sum=0, delta=0x9E3779B9; for (i=0; i < num_rounds; i++) { v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); sum += delta; v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]); } v[0]=v0; v[1]=v1; } 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() { uint32_t encode_data[]={ 0x168F8672,0x2DBD824,0x0CF647FCA,0x0E6EFA7EF,0x4AE016F0,0x0C5832E1D,0x455C0A05, 0x0FFEB8140,0x0BE9561EF,0x7F819E23,0x3BC04269,0x0C68B825B,0x0E6A5B1F0,0x0BD03CBBD, 0x0A9B3CE0E,0x6C85E6E7,0x9F5C71EF,0x3BE4BD57 }; uint32_t const key[] = {0xDEADBEEF,0x87654321,0xFACEB00C,0xCAFEBABE}; unsigned int r=32;//num_rounds建议取值为32 // v为要加密的数据是两个32位无符号整数 // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位 // printf("加密前原始数据:%u %u\n",v[0],v[1]); // encipher(r, v, k); // printf("加密后的数据:%u %u\n",v[0],v[1]); uint32_t tmp[2] = {0}; for(int i = 0; i < sizeof(encode_data)/sizeof(uint32_t); i+=2) { tmp[0] = encode_data[i]; tmp[1] = encode_data[i+1]; decipher(r,tmp, key); printf("%s",tmp); } return 0; }flagDASCTF{Don't_forget_to_drink_tea} NewStarCTF 2023 Week2 reverse easy_enc https://dirtycow.cn/173.html 2023-11-02T20:30:00+08:00 思路:直接爆破exp:#include <stdio.h> #include <string.h> int main() { int enc[] = { 0xE8, 0x80, 0x84, 0x08, 0x18, 0x3C, 0x78, 0x68, 0x00, 0x70, 0x7C, 0x94, 0xC8, 0xE0, 0x10, 0xEC, 0xB4, 0xAC, 0x68, 0xA8, 0x0C, 0x1C, 0x90, 0xCC, 0x54, 0x3C, 0x14, 0xDC, 0x30 }; char key[] = "NewStarCTF"; for(int i =0; i < 29; i++) { for(int j = 33; j < 127; j++) { int tmp = j; if(tmp >= 'A' && tmp <= 'Z') { tmp = (tmp - 52) % 26 + 65; } else if(tmp >= '0' && tmp <= '9') { tmp = (tmp - 45) % 10 + 48; } else if(tmp >= 'a' && tmp <= 'z') { tmp = (tmp - 89) % 26 + 97; } tmp += key[i % strlen(key)]; tmp = ~tmp; tmp = (unsigned char)(tmp * 52); if(tmp == enc[i]) { if((j >= 'A' && j <= 'Z') || (j >= 'a' && j <= 'z')) { printf("%c", j); break; } } } } return 0; }flag:BruteForceIsAGoodwaytoGetFlag NewStarCTF 2023 Week2 reverse Random_1 https://dirtycow.cn/172.html 2023-11-02T18:20:00+08:00 思路:思路就是爆破要注意windows的srand()函数和Linux的srand()函数不一样,要放在linux中运行exp:#include <stdio.h> #include <stdlib.h> int main() { unsigned char enc[] = { 0xEE, 0xE6, 0xD7, 0xB2, 0x8A, 0xAB, 0x13, 0x35, 0x02, 0x7B, 0xC9, 0xB9, 0x9C, 0xBA, 0xED, 0x2E, 0xBD, 0x4F, 0xFA, 0xEE, 0xC8, 0xF8, 0xE4, 0x16, 0x82, 0x63, 0x3B, 0x98, 0xF4, 0x14, 0x30, 0x38, 0x07, 0x36, 0x84, 0x3D, 0x0C, 0x36, 0x32, 0xEA, 0x55, 0xA6 }; unsigned char Table[] = { 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 }; srand(0x7261745377654E); int v4 = 0; int v3 = 0; char flag[43] = {0}; for(int j = 0; j < 42; j++ ) { v4 = rand(); for(int i = 32; i < 127; i++) { v3 = i; if(enc[j] == Table[(16 * ((v3 + v4 % 255) >> 4) + 15) & (v3 + v4 % 255)]) { flag[j] = i; break; } } } printf("%s", flag); return 0; }flag:flag{B8452786-DD8E-412C-E355-2B6F27DAB5F9} NewStarCTF 2023 SMC https://dirtycow.cn/170.html 2023-10-25T17:48:00+08:00 思路:拿到题目,先使用exeinfo查壳image-20231025165019875.png程序是无壳32位使用ida打开,查看伪代码image-20231025165121623.png大概过一遍程序将用户输入保存在unk_4033D4之后有个反调试,然后调用了sub_401042()函数接下来是一个判断,判断flag是否正确,但是ida没有识别出来这个函数,应该是被加密了跟进sub_401042()函数查看image-20231025165803500.png这个函数对数组byte_403040进行了操作,这个数组就是判断flag时调用的函数我们只要动调到sub_401042()函数执行完就可以看到验证flag的函数因为程序有反调试,我们在检测反调试的地方下个断点image-20231025172019455.png调试启动!!!输入flag之后程序停在了跳转这边image-20231025172126171.pngjz是判断zf标志位来跳转的image-20231025172541644.png我们只要修改zf标志位就能控制跳转,将zf改成1,在判断flag的的地方下个断点,继续运行image-20231025173030609.png按f7于运行一步,双击进入byte_403040image-20231025173250544.pngida已经识别出指令了,在函数头按P创建函数,再按f5查看伪代码image-20231025173341591.png现在已经能看到flag的验证函数了用户输入的数据异或0x11再加5等于加密字符串,我们只要将加密flag反正运算一下就能得到flag接下来写expexp:双击进入unk_403020,选中shift+e就能提取加密flag的数据image-20231025174343190.pngenc = [ 0x7C, 0x82, 0x75, 0x7B, 0x6F, 0x47, 0x61, 0x57, 0x53, 0x25, 0x47, 0x53, 0x25, 0x84, 0x6A, 0x27, 0x68, 0x27, 0x67, 0x6A, 0x7D, 0x84, 0x7B, 0x35, 0x35, 0x48, 0x25, 0x7B, 0x7E, 0x6A, 0x33, 0x71 ] flag = '' for i in range(32): flag += chr((enc[i] - 5) ^ 0x11) print(flag)flag:flag{SMC_1S_1nt3r3sting!!R1ght?} BUUCTF [FlareOn6]Overlong https://dirtycow.cn/54.html 2023-10-19T21:49:00+08:00 思路:拿到题目 使用exeinfo查看程序信息是一个无壳32位程序image-20230407103641150.png直接ida分析 v6是sub_401160函数的返回值Text[v6] = 0 在c语言中字符串是以0结尾的 这里的意思是取v6的值为字符串长度查看sub_401160函数的参数是Text &unk_402008 28image-20230407110654182.png双击&unk_402008查看值发现这是个数组image-20230409194556653.png转换一下是一个长度为176的数组image-20230409194644102.png跟进sub_401160函数查看image-20230409194415881.png继续跟进sub_401000函数这个函数对Text进行了操作image-20230409195258303.png运行程序查看发现程序消息框的内容正好是28位 也就是sub_401160函数中的第三个参数 循环的次数大胆猜想 每循环一次就处理一个&unk_402008中的字符&unk_402008中有176个字符 去掉最后一位0 就是175分字符我们只要把28次循环改成175次就可以得到flagimage-20230409200207447.png现在有两种解题思路1.将程序的代码dump下来 将循环次数改成1752.使用动调 直接将循环次数改成175我选第二种方法(太懒了)exp:使用x32dbg打开程程序发现内存地址和ida中的内存地址不一样image-20230409201225904.png接下来计算偏移地址找一个比较明显的特征就这个push Outputimage-20230409201607101.png在动调中搜索字符串image-20230409201800012.png找到output双击进去image-20230409201844690.png在动调中的内存地址为003E11EFida中的地址为004011EF将这两个地址相减就是偏移地址了image-20230409202108436.png在ida中找到push 1Ch 复制他的内存地址在动调中跳转到这个地址-20000image-20230409202254106.pngimage-20230409202454745.pngimage-20230409202508746.png右键这个地址->在内存窗口中转到->选定的地址image-20230409202557852.png右键这个1C->修改image-20230409202735076.png修改成AF(十进制的175)image-20230409202837372.png按f9运行程序image-20230409203006505.pngflag:flag{I_a_M_t_h_e_e_n_C_o_D_i_n_g@flare-on.com} BUUCTF [FlareOn3]Challenge1 https://dirtycow.cn/31.html 2023-10-19T16:00:39+08:00 思路:使用exeinfo查壳是一个无壳32位的程序image-20230409204347007.png直接上ida直接看main函数将用户的输入保存到buffer[]使用sub_401260函数处理buffer[] Str1指向处理之后sub_401260的返回值最后比较Str1和Str2的值image-20230410083548517.png跟进sub_401260函数查看瞅一眼代码 发现很眼熟 看着像base64继续往下看image-20230410090133409.png看到了byte_413000 双击进去查看发现了对base64的编码表进行了修改image-20230410090457886.png到这里题目的逻辑已经很清晰了直接写脚本跑flagexp:import base64 def main(): string1 = "ZYXABCDEFGHIJKLMNOPQRSTUVWzyxabcdefghijklmnopqrstuvw0123456789+/" string2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" encode = "x2dtJEOmyjacxDemx2eczT5cVS9fVUGvWTuZWjuexjRqy24rV29q" print(base64.b64decode(encode.translate(str.maketrans(string1,string2)))) if __name__ =="__main__": main()flag:flag{sh00ting_phish_in_a_barrel@flare-on.com} BUUCTF [HDCTF2019]Maze https://dirtycow.cn/26.html 2023-10-19T15:47:00+08:00 思路:下载题目,首先使用exeinfo查壳image-20230322162405703.png查出来是upx的壳 尝试使用脱壳工具脱壳脱完壳使用ida打开image-20230322200320034.png看到了jnz 有call了一个错误的函数 很明显是一个花指令选中那一行 在ida中点击edit->Path program->Change program bytesimage-20230327140907211.png将e8修改成90在汇编指令中e8是call 90是nop修改好之后选中红色区域 按p 创建函数 就可以发现 现在可以反汇编了image-20230327141223023.png按f5进行反汇编image-20230327141315767.png发现程序判断用户输入是否为a d s w 对asc_408078 和 dword_40807C进行操作然后通过题目名maze翻译过来就是迷宫 猜测通过用户的输入 移动一个坐标 找到flagimage-20230327151715623.png查看asc_408078的初始值是7image-20230327151810009.png查看dword_40807C 初始值是0经过一系列操作之后要使asc_408078 == 5 和 dword_40807C == -4 也是就是起始点(7,0)->终点(5,-4)image-20230327152443143.pngshift+f12查找字符串 看到了一个很可疑的字符串 看似是个迷宫把它复制出来从坐标得知 F 在第-4行 也就是说 f上面还有4行(0,-1,-2,-3)F是-4行第5个, 也就是前面还有5个 排一下版image-20230327183620752.pngflag:flag{ssaaasaassdddw}