Xunflash的小站
type: channel
link: https://www.xunflash.top/
description: 真不戳
items: 有人想起来还有个博客在这🤓👆
items: 【Reverse】2023浙江省大学生网络安全技能竞赛预赛WriteUp
items: 【Linux/Android】移植新安卓设备到kupfer archlinuxarm / Porting a new device to kupfer archlinuxarm
items: 【CTF】Rust逆向，BeingDebugged，异或取表算法逆向 内存取证 2023上海市赛初赛
items: 【Reverse】Angr_ctf项目学习
items: 【Reverse】2023腾讯游戏安全决赛WriteUp （未完成）
items: 【逆向学习】Windows平台下的DLL注入
items: 【逆向学习】Inline Hook学习
items: 【逆向学习】TLS_Callback TLS回调函数学习以及出题思路
items: 【CTF】2023铁人三项赛第一赛区 初赛 逆向方向WP

有人想起来还有个博客在这🤓👆
type: item
date: 2024-10-24T13:34:00+00:00
description: 有人想起来还有个博客在这🤓👆差点就完成拖更一年的成就了 好险。。。🤗

【Reverse】2023浙江省大学生网络安全技能竞赛预赛WriteUp
type: item
date: 2023-11-07T10:04:50+00:00
description: 好像好久好久没更新博客了，水一篇WP好了排名4AK了逆向 多亏了@woodwhale教我lua，不然歇逼了题目没啥难度，就是老喜欢自己写算法挺恶心人的。pycccpycdc直接出代码，异或脚本即可check = [ 102, 109, 99, 100, 127, 52, 114, 88, 97, 122, 85, 125, 105, 127, 119, 80, 120, 112, 98, 39, 109, 52, 55, 106] for i in range(len(check)): print(chr(check[i] ^ i),end='') luare断点到000055C07F31848C可以搜内存搜到\x1bLua，dump出来binary形式的lua脚本 用unluac即可反编译出来，可以看到调用了Oo00Oo0Oo00Oo0是一个取表替换的算法，写脚本解密即可lines = '''0x60856D1028C8953C 0x964849764CB30359 0x2E7164C479B75FB8 0x80637291A7AC8C38 0x7B8BF3AE4B339EB0 0xCFE06FEC52B45B4D 0x5DC67EAAB20C3AD 0x24FCFBD656409F00 0x4AF00D463D0BCA92 0x7DBC8A3B1A11555A 0x3061CE7513A9E76C 0x9C54D007276AA614 0x34C20158D8898E5C 0x50A02AC02F3569E8 0xC0E681D39FF8836 0xB66E7F18FEB1E693 0x29F5D2E92B315378 0x41D9DBDE84172C0F 0x7A45A899A1F71906 0xE5AA0AAF1BA5233E 0x9A3A82FAF8E1A4EF 0xC1D173C7651C8FDF 0x8D9DDD875EA2D7C5 0x66EE9790CD81C9F9 0x370874C63F424FDA 0xB93283E32677CB25 0xBA2D4ED544F2D3BD 0xBFE421121E049862 0xA31694FDF486F647 0x430251B27C701FEB 0x5DE26B097ECC1522 0xF157EDD4B5BE9BBB''' from pwn import * global_data = [] def pares(data): x = p64(int(data.strip(), 16)) global_data.extend(list(x)) for l in lines.splitlines(): pares(l.strip()) print(global_data) res = [ 109, -73, -72, 46, -73, -5, 99, -100, 46, 59, 32, -76, 109, 3, 59, 20, -61, -56, -119, 48, 100, 118, 36, 118, 82, 3, 95, 106, 14, -80, 5, -89, 89, -85, 5, 14, 46, -73, 7, 127] flag = '' from ctypes import c_uint8 last = global_data.index(res[-1]) flag += chr(last) for i in range(39): x = -i - 2 last = c_uint8(c_uint8(global_data.index(c_uint8(res[x]).value)).value ^ last).value flag += chr(last) flag = flag[::-1] print(flag)easyapkDES的名，AES的心，main替换了一下key的字符直接cyberchefAndroidELF魔改UPX，改回来就可以unpack中间这个就是加密具体的不截图了，看脚本即可，分别对应四个函数的解密from ctypes import c_uint8 enc = [0x3D, 0x45, 0x38, 0x7E, 0x78, 0x4B, 0x6A, 0x5C, 0x5B, 0x52, 0x4C, 0x73, 0x4E, 0x39, 0x49, 0x5F, 0x49, 0x40, 0x38, 0x5E, 0x74, 0x40, 0x66, 0x44, 0x46, 0x7A, 0x39, 0x3B, 0x67, 0x39, 0x70, 0x6C, 0x71, 0x5E, 0x6D, 0x4D, 0x5A, 0x4C, 0x7F, 0x…

【Linux/Android】移植新安卓设备到kupfer archlinuxarm / Porting a new device to kupfer archlinuxarm
type: item
date: 2023-05-23T04:53:00+00:00
description: 移植新设备到kupfer/Porting a new device to kupferbootstrap准备工作首先你要拥有：linux环境（wsl也可以）python环境（用于安装kupferbootstrap）安卓设备安装kupferbootstrap参考https://kupfer.gitlab.io/kupferbootstrap/main/install/Install Python 3, Docker, and git.On Arch: pacman -S python docker git --needed --noconfirmHintAfter installing Docker you will have to add your user to the docker group:sudo usermod -aG docker "$(whoami)"Then restart your desktop session for the new group to take effect.Pick which Kupferbootstrap branch to clone: usually either main or devClone the repository: git clone -b INSERT_BRANCHNAME_HERE https://gitlab.com/kupfer/kupferbootstrapChange into the folder: cd kupferbootstrapInstall python dependencies: pip3 install -r requirements.txtNoteMost of our python dependencies are available as distro packages on most distros, sadly it’s incomplete on Arch.See requirements.txt for the list of required python packages.Symlink kupferbootstrap into your $PATH: sudo ln -s "$(pwd)/bin/kupferbootstrap" /usr/local/bin/You should now be able to run kupferbootstrap --help!初始化＆配置文件修改你可以输入kupferbootstrap config init -N来快速新建一个默认的配置文件，默认位于~/.config/kupfer/kupferbootstrap.toml生成后可以使用vim编辑toml配置文件，重点注意pkgbuilds和profiles.default这两块。下面是一份kupferbootstrap.toml的示例[wrapper] type = "none" [build] ccache = true clean_mode = true crosscompile = true crossdirect = true threads = 8 [pkgbuilds] git_repo = "https://gitlab.com/kupfer/packages/pkgbuilds.git" git_branch = "dev" [pacman] parallel_downloads = 4 check_space = false repo_branch = "dev" [paths] cache_dir = "/home/xunflash/.cache/kupfer" chroots = "%cache_dir%/chroots" pacman = "%cache_dir%/pacman" packages = "%cache_dir%/packages" pkgbuilds = "%cache_dir%/pkgbuilds" jumpdrive = "%cache_dir%/jumpdrive" images = "%cache_dir%/images" ccache = "%cache_dir%/ccache" rust = "%cache_dir%/rust" [profiles] current = "default" [profiles.default] parent = "" device = "sm8250-xiaomi-elish-csot" flavour = "plasma-desktop" pkgs_include = ["konsole","vim","git","chromium"] p…

【CTF】Rust逆向，BeingDebugged，异或取表算法逆向 内存取证 2023上海市赛初赛
type: item
date: 2023-05-22T17:49:00+00:00
description: 上海市赛初赛两个简单题拿了三血，还摸了两题Misc，最开始比赛没沉下心还是浪费了一些时间，感觉应该能更好的。近期来打的比较爽的一次比赛。两题逆向都0解，后面也没深究了...感觉不如MiscReverseexEXE这边一个beingdebugged反调试，noplpAddress里面一个rc4sub_401535是base64，所以就是RC4+base64，直接cyberchef解密就行encrytor大致流程：获取固定的DateTime 16574669，然后获取当前时间，并转换成10进制的Dword数组，获取分钟和秒钟相乘，将获得的数转换为字符串，然后经过SHA256加密，得到的值作为RC4的key对flag.txt进行加密，输出到flag.txt.enc中关键函数：出题时间可以通过文件修改时间查看考虑到程序运行时间，最后取的是33*41=1353rc4解密即可flag在哪？保存了一些函数的地址，重命名一下动调到这里进去p一下，下面call的analyse有问题，nop掉然后看汇编即可可以看到是有一个表，然后nop掉的位置是call了一个memcpy进去的东西看一下Src中间的内容这边也是出题人自己实现的一个算法提取出byte_406274的密文写脚本解密即可enc = [0xD3, 0x38, 0xD1, 0xD3, 0x7B, 0xAD, 0xB3, 0x66, 0x71, 0x3A, 0x59, 0x5F, 0x5F, 0x2D, 0x73] key = 'e4bdtRV02\x00\x00\x00\x00\x00\x00' flagbox = [0x66, 0x6C, 0x61, 0x67, 0x7B, 0x77, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x74, 0x6F, 0x6D, 0x7D, 0x00, 0x00, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x4D, 0x79, 0x20, 0x63, 0x68, 0x65, 0x65, 0x73, 0x65, 0x7D, 0x00, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x69, 0x20, 0x6D, 0x69, 0x73, 0x73, 0x20, 0x74, 0x6F, 0x6D, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x6C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x66, 0x75, 0x6E, 0x7D, 0x00, 0x00, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x75, 0x20, 0x77, 0x61, 0x6E, 0x74, 0x20, 0x73, 0x74, 0x65, 0x61, 0x6C, 0x20, 0x6D, 0x79, 0x20, 0x63, 0x68, 0x65, 0x65, 0x73, 0x65, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x69, 0x20, 0x68, 0x61, 0x76, 0x65, 0x64, 0x20, 0x6C, 0x6F, 0x73, 0x74, 0x20, 0x61, 0x20, 0x63, 0x68, 0x65, 0x65, 0x73, 0x65, 0x7D, 0x00, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x63, 0x68, 0x65, 0x65, 0x73, 0x65, 0x20, 0x69, 0x73, 0x20, 0x6D, 0x79, 0x20, 0x6C, 0x69, 0x66, 0x65, 0x7D, 0x00, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x69, 0x64, 0x20, 0x79, 0x6F, 0x75, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x62, 0x72, 0x65, 0x61, 0x6B, 0x66, 0x61, 0x73, 0x74, 0x7D, 0x00, 0x00, 0x00, 0x66, 0x6C, 0x61, 0x67, 0x7B, 0x6C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x68, 0x61, 0x76, 0x6…

【Reverse】Angr_ctf项目学习
type: item
date: 2023-05-11T14:06:00+00:00
description: Angr学习上次面山石的时候，对面的师傅让我跟随这个angr_ctf的项目来学一学，那来试试看配置安装Angr首先得先装上Angr吧，先根据Angr官方文档上面的指引：https://docs.angr.io/introductory-errata/install*nix系列的系统均可以这样安装sudo apt-get install python3-dev libffi-dev build-essential virtualenvwrapper mkvirtualenv --python=$(which python3) angr && pip install angr有的系统的Virtualenv的路径有些奇怪，可以在apt安装完之后加一句source `which virtualenvwrapper.sh`拉取angr_ctf仓库使用git拉取git clone https://github.com/jakespringer/angr_ctf.git根据readme可以知道，使用package.py可以直接打包所有题目，我们在刚刚的virtualenv环境中运行python3 package.py ./package即可在package目录下得到所有编译好的文件了。00_angr_find使用ida打开，可以观察到就是一个非常正常的check程序。可以使用angr快速解题我们看看对应的示例脚本顶部是对脚本使用的介绍以及对于ctf的简单介绍。# Before you begin, here are a few notes about these capture-the-flag # challenges. # # Each binary, when run, will ask for a password, which can be entered via stdin # (typing it into the console.) Many of the levels will accept many different # passwords. Your goal is to find a single password that works for each binary. # # If you enter an incorrect password, the program will print "Try again." If you # enter a correct password, the program will print "Good Job." # # Each challenge will be accompanied by a file like this one, named # "scaffoldXX.py". It will offer guidance as well as the skeleton of a possible # solution. You will have to edit each file. In some cases, you will have to # edit it significantly. While use of these files is recommended, you can write # a solution without them, if you find that they are too restrictive. # # Places in the scaffoldXX.py that require a simple substitution will be marked # with three question marks (???). Places that require more code will be marked # with an ellipsis (...). Comments will document any new concepts, but will be # omitted for concepts that have already been covered (you will need to use # previous scaffoldXX.py files as a reference to solve the challenges.) If a # comment documents a part of the code that needs to be changed, it will be # marked with an exclamation point at the end, on…

【Reverse】2023腾讯游戏安全决赛WriteUp （未完成）
type: item
date: 2023-04-23T08:10:42+00:00
description: 题解报告脱壳首先，程序加了一个VMP3.0.0-VMP3.5.0的壳，要对程序进行脱壳，我选用的是断点在CreateToolhelp32Snapshot这个api的后几位，程序到达这里之后再对vmp0段下内存执行断点。再次f9即可到达oep。程序执行流分析1程序oep被虚拟化保护了，因此想要静态分析依然很困难，可以通过x64dbg的dump工具dump出来，可以看到一些敏感字符，由于程序被虚拟化保护了，我们只能通过这些数据的地址来定位函数地址。首先对下方的error信息进行信息收集，可以很快的发现这个错误出自远程线程注入的代码中。那么其实可以知道程序中其实是带有一个远程线程注入的功能的。而对程序的进程信息进行分析，可以了解到程序将DLL注入到了taskmgr.exe和explorer.exe中，并且会反复的对程序进行重启。杀死进程思路通过以上的分析，可以得到该程序进程守护的原理，那么想要杀死进程则可以通过一个简单的方法即在杀死程序进程的同时一起杀死taskmgr.exe和explorer.exe。示例代码#include <stdio.h> #include <windows.h> #include "tchar.h" #include <TlHelp32.h> //通过进程快照获取PID int* _GetProcessPID(LPCTSTR lpProcessName) { int Ret[10]; PROCESSENTRY32 p32; HANDLE lpSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (lpSnapshot == INVALID_HANDLE_VALUE) { printf("获取进程快照失败,请重试! Error:%d", ::GetLastError()); return Ret; } p32.dwSize = sizeof(PROCESSENTRY32); ::Process32First(lpSnapshot, &p32); int i = 0; do { if (!lstrcmp(p32.szExeFile, lpProcessName)) { Ret[i] = p32.th32ProcessID; i++; } } while (::Process32Next(lpSnapshot, &p32)); ::CloseHandle(lpSnapshot); return Ret; } BOOL MyTerminate(int pid) { int ret; HANDLE hProcess; if (pid > 32768 || pid <= 0) { return 0; } hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (INVALID_HANDLE_VALUE == hProcess) { fprintf(stderr, "Error: Can not open specified process!\n"); fprintf(stderr, "Error code: %d\n", GetLastError()); return 0; } ret = TerminateProcess(hProcess, 0); if (ret == FALSE) { printf("Error: Can not terminate specified process!\n"); printf("Error code: %d\n", GetLastError()); } CloseHandle(hProcess); } int main(int argc, char* argv[]) { int* explorerProcessId; int* WorkingServiceProcessId; int* taskmgrProcessId; //获取三个需要杀死的进程的pid explorerProcessId = _GetProcessPID(L"explorer.exe"); WorkingServiceProcessId = _GetProcessPID(L"WorkingService.exe"); taskmgrProcessId = _GetProcessPID(L"taskmgr.exe"); //杀死所有名为WorkingService.exe的进程（已测试不会同时出现10个WorkingService.exe的进程，简化处理） for(int i = 0;i < 10;i++){ printf("%d\n", WorkingServiceProc…

【逆向学习】Windows平台下的DLL注入
type: item
date: 2023-03-14T08:41:11+00:00
description: DLL注入通过DLL注入可以对其他进程进行hook/热补丁/修复BUG，同时也是渗透其他进程的有效方法。DLL被加载到进程后会自动运行DIIMain()函数，用户可以把想执行的代码放到DIIMain()函数，每当加载DLL时，添加的代码就会自然而然得到执行。利用该特性可修复程序Bug，或向程序添加新功能。本篇博客将使用Inline Hook和DLL注入技术实现控制程序执行流DLL注入流程使用MS编译dll动态链接库后，可以通过一些常见的方式进行DLL的注入：创建远程线程（CreateRemoteThread() API）使用注册表（AppInit_DLLs值）消息勾取（SetWindowsHookEx() API）通过这些方法编写注入程序，然后对写有Inline Hook逻辑的DLL程序进行加载并且注入进目标进程代码编写DLL编写DLL加载到进程后会运行DllMain()函数，通过这个特点，我们可以修改上一篇博客中的Inline Hook代码为如下代码其中，DllMain()参数中的ul_reason_for_call与之前TLS_Callback学习博客中的dwReason是相同的。因此，在进程启动的时候我们调用InlineHook()对MessageBoxA()进行hook// dllmain.cpp : 定义 DLL 应用程序的入口点。 #include "pch.h" #include <windows.h> #include <stdio.h> #include <iostream> #include <tchar.h> //修改API入口为 jmp xxx 使得程序能跳转到自己的函数 BYTE __NewCode[7] = { 0xE9, 0x0, 0x0, 0x0, 0x0 }; BYTE __OldCode[7] = { 0 }; FARPROC Messagebox_FARPROC; HMODULE g_hMod; int WINAPI MyMessageBoxA( HWND hWnd, // handle to owner window LPCTSTR lpText, // text in message box LPCTSTR lpCaption, // message box title UINT uType // message box style ); void InlineHook() { DWORD dwOldProtect = 0; //首先获取user32.dll的模块句柄 HMODULE user32_HMODULE = LoadLibraryA("user32.dll"); //利用GetProcAddress获取MessageBoxA导出函数的地址 Messagebox_FARPROC = GetProcAddress(user32_HMODULE, "MessageBoxA"); //利用ReadProcessMemory读取内存中MessageBoxA的前5字节 if (!ReadProcessMemory(GetCurrentProcess(), Messagebox_FARPROC, __OldCode, 6, NULL)) { printf("[!] ReadProcessMemory Failed"); } printf("%x%x%x%x%x\n", __OldCode[0], __OldCode[1], __OldCode[2], __OldCode[3], __OldCode[4]); //E9跳转为jmp地址到目标地址的间隔，地址需要进行计算，计算出来后赋值给newcode的后4位 *((ULONG*)(__NewCode + 1)) = (ULONG)&MyMessageBoxA - ((ULONG)Messagebox_FARPROC + 5); //memcpy(&__NewCode[1], &JmpAddress, 4); printf("JmpAddress : %x\n", *((ULONG*)(__NewCode + 1))); //将权限替换为可读写执行 VirtualProtect(Messagebox_FARPROC, 6, PAGE_EXECUTE_READWRITE, &dwOldProtect); //直接写入内存 WriteProcessMemory(GetCurrentProcess(), Messagebox_FARPROC, __NewCode, 5, NULL); //恢复之前的权限 VirtualProtect(Messagebox_FARPROC, 6, dwOldProtect, &dwOldProtect); } int …

【逆向学习】Inline Hook学习
type: item
date: 2023-03-09T11:37:46+00:00
description: inline hook主要思想：1、构造跳转指令。2、在内存中找到欲HOOK函数地址，并保存欲HOOK位置处的原本字节。3、将构造的跳转指令写入需HOOK的位置处。4、当被HOOK位置被执行时会转到我们的流程执行。5、如果要执行原来的流程，那么恢复HOOK，也就是还原被修改的字节。 6、执行函数原来的流程。hook方式这部分其实参考了网上很多文章，自己感觉这些文章光写文字还是缺少一些对比，所以自己思考然后patch出来一些代码，自己理解与展示的更方便1、call跳转后修改系统函数众所周知，ms的库函数是从一条MOV EDI, EDI指令开始的，这是因为在运行时，如果需要一个填充字节，则会填充一条NOP指令，如果需要两个字节来填充，则会填充一条MOV EDI, EDI指令。这样当hook时就有了五个字节给我们进行操作，可以对MessageBoxW的前五个字节（固定的mov edi,edi push ebp mov ebp,esp）进行修改，将其替换为一个五字节的近距离地址跳转的jmp指令跳转到我们自行构造的函数中。至于修改字节，有几种方式，《加密与解密》中记录了jmp xxxxxxxx;push xxxxxxxx/retn;mov eax,xxxxxxxx/jmp eax;这几种方式。代码实现：#include <windows.h> #include <stdio.h> #include <iostream> #include <tchar.h> //修改API入口为 jmp xxx 使得程序能跳转到自己的函数 BYTE __NewCode[7] = { 0xE9, 0x0, 0x0, 0x0, 0x0 }; BYTE __OldCode[7] = { 0 }; FARPROC Messagebox_FARPROC; int WINAPI MyMessageBoxA( HWND hWnd, // handle to owner window LPCTSTR lpText, // text in message box LPCTSTR lpCaption, // message box title UINT uType // message box style ); void InlineHook(); void main() { InlineHook(); //调用MessageBoxA MessageBoxA(NULL, "Hello World", "Title", MB_OK); } void InlineHook() { DWORD dwOldProtect = 0; //首先获取user32.dll的模块句柄 HMODULE user32_HMODULE = LoadLibraryA("user32.dll"); //利用GetProcAddress获取MessageBoxA导出函数的地址 Messagebox_FARPROC = GetProcAddress(user32_HMODULE, "MessageBoxA"); //利用ReadProcessMemory读取内存中MessageBoxA的前5字节 if (!ReadProcessMemory(GetCurrentProcess(), Messagebox_FARPROC, __OldCode, 6, NULL)) { printf("[!] ReadProcessMemory Failed"); } printf("%x%x%x%x%x\n", __OldCode[0], __OldCode[1], __OldCode[2], __OldCode[3], __OldCode[4]); //E9跳转为jmp地址到目标地址的间隔，地址需要进行计算，计算出来后赋值给newcode的后4位 *((ULONG*)(__NewCode + 1)) = (ULONG)&MyMessageBoxA - ((ULONG)Messagebox_FARPROC + 5); //memcpy(&__NewCode[1], &JmpAddress, 4); printf("JmpAddress : %x\n", *((ULONG*)(__NewCode + 1))); //将权限替换为可读写执行 VirtualProtect(Messagebox_FARPROC, 6, PAGE_EXECUTE_READWRITE, &dwOldProtect); //直接写入内存 WriteProcessMemory(GetCurrentProcess(), Messagebox_FARPROC, __NewCode, 5, NULL); //恢复之前的权限 VirtualProtect(Mes…

【逆向学习】TLS_Callback TLS回调函数学习以及出题思路
type: item
date: 2023-03-08T07:05:00+00:00
description: TLS_CallbackTLS_Callback（Thread-local storage，线程本地存储）是WindowsAPI下的一个回调函数，它会在程序进程开始，结束以及线程开始，结束的时候调用。MSDN地址TLS在逆向中TLS_Callback在逆向中有一个特点： 先于main函数执行/在main结束后执行。因此也经常被用作反调试，或者是藏匿变量修改，以防止动态和静态分析。代码实现参考此处#include <stdio.h> #include <Windows.h> #ifdef _WIN64 #pragma comment (linker, "/INCLUDE:_tls_used") #pragma comment (linker, "/INCLUDE:thread_callback_base") #else #pragma comment (linker, "/INCLUDE:__tls_used") #pragma comment (linker, "/INCLUDE:_thread_callback_base") #endif void generate_str(char* ptr, DWORD reason) { switch (reason) { case DLL_PROCESS_ATTACH: strcat_s(ptr ,200, "DLL_PROCESS_ATTACH\n"); break; case DLL_PROCESS_DETACH: strcat_s(ptr, 200, "DLL_PROCESS_DETACH\n"); break; case DLL_THREAD_ATTACH: strcat_s(ptr, 200, "DLL_THREAD_ATTACH\n"); break; case DLL_THREAD_DETACH: strcat_s(ptr, 200, "DLL_THREAD_DETACH\n"); break; } } // TLS回调 void NTAPI tls_callback_1(PVOID DllHandle, DWORD Reason, PVOID Reserved) { HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); char ptr[256]{ 0 }; strcpy_s(ptr, " TLS Callback1: "); generate_str(ptr, Reason); WriteConsoleA(hStdout, ptr, strlen(ptr), NULL, NULL); } // TLS回调 void NTAPI tls_callback_2(PVOID DllHandle, DWORD Reason, PVOID Reserved) { HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); char ptr[256]{ 0 }; strcpy_s(ptr, " TLS Callback2: "); generate_str(ptr, Reason); WriteConsoleA(hStdout, ptr, strlen(ptr), NULL, NULL); } #ifdef _WIN64 #pragma const_seg(".CRT$XLF") EXTERN_C const #else #pragma data_seg(".CRT$XLF") EXTERN_C #endif PIMAGE_TLS_CALLBACK thread_callback_base[] = { tls_callback_1, tls_callback_2, 0 }; #ifdef _WIN64 #pragma const_seg() #else #pragma data_seg() #endif //_WIN64 #define OK_PRINT_FLAG(s) ("\033[1;40;32m[+]\033[0m "##s) #define ERR_PRINT_FLAG(s) ("\033[1;40;31m[-]\033[0m "##s) // 线程回调 DWORD WINAPI thread_func( _In_ LPVOID lpParameter ) { printf(OK_PRINT_FLAG("Enter thread func...\n")); Sleep(5000); printf(OK_PRINT_FLAG("Leave thread func...\n")); return 0; } int main(void) { printf(OK_PRINT_FLAG("Ent…

【CTF】2023铁人三项赛第一赛区 初赛 逆向方向WP
type: item
date: 2023-01-10T13:39:46+00:00
description: ReverseHelloWorld看图片注释写的很明白，直接分析程序逻辑就行，题目先生成了个随机数，然后给了个字母表，题目要求输出HelloWorld，观察到最后cout是输出这个output的内容，output也是程序开始random随机出来的内容观察到程序对output进行了修改，分析可以分析出来每轮循环读入2字节的数据，提取第一个字节的高4bit和低4bit，这里直接方便看改成了hibyte和lowbyte（自己能理解是什么就行）高位作为下面进入各个分支的条件，低位作为控制output的下标。每轮的第二个字节只在赋值区域被用到，作为字符表的索引。构造输入即可print('0'+chr(7)+'1'+chr(4)+'2'+chr(11)+'3'+chr(11)+'4'+chr(14)+'5'+chr(22)+'6'+chr(14)+'7'+chr(17)+'8'+chr(11)+'9'+chr(3)+chr(0x10)+chr(1)+chr(0x15)+chr(1)+chr(0x4A)+chr(1)) #'0'字符为0x30，高4bit为3进入了赋值的if分支，低bit作为控制output的idx #前有v9=&11[1]&31，31即0b11111，v9仅作为赋值分支中v27也就是控制字母表的idx使用 #因此第一组0x30 0x7意思是进入赋值分支，控制输出的第0位，赋值为字母表中idx为7的字母 #后面以此类推 #0x10 0x1 0x15 0x1的意思是把第0位和第5位的字母变大写 #0x4A 0x1的意思是进入4分支 也就是00截断，在0xA的位置写入一个0x0 截断输出 #最后利用管道符把python的输出直接输出到远程上 #python ./re2.py | nc 172.31.0.157 50000rand5可以看出来是五次换表，伪随机生成的表，动调把五张表拿出来直接用cyberchef解就行