re-part-5-2
由于re-part-5字数太多了,所以另开一个帖子,也是记录剩下的难度5的题解。
asong
题目一共3个文件,asong是一个64位的ELF、out文件是一个二进制文件、that_girl是一个有好多句子的文件。
这个题目,就是使用that_girl文件,结合flag,最后生成一个out文件,题目思路比较简单,就是函数逆向有点麻烦,花费了大概6h,脚本如下:
1 | #!/usr/bin/env python |
pseudorandom
看题目,假随机,猜测是要生成一段随机数,种子是flag。是64位的ELF。仔细调研后发现,C语言中,如果不提前使用srand来设置种子值,而是直接使用rand来生成随机数,此时生成的随机数序列是固定的。
C语言中配置openssl库的方法为:https://blog.csdn.net/CHTXRT/article/details/128771974
有一个坑,就是在Linux下,使用C语言使用rand产生随机数,第一个数总是1804289383;然而在windows中,第一个数总是41。这是因为在不同的操作系统中,rand函数使用的随机数生成算法不同。在Linux下,rand函数使用的是线性同余算法(linear congruential generator),其计算公式是:next = (prev * a + c) % m。其中,prev是上一个随机数,a、c、m是常数。在Linux下,a=1103515245, c=12345, m=2147483648,因此第一个随机数总是1804289383。而在Windows下,rand函数使用的是另一种随机数生成算法,其计算公式也是线性同余算法,但参数不同。在Windows下,a=214013, c=2531011, m=2^31,因此第一个随机数总是41。
补充:ubuntu下编译含有openssl的程序g++ -o pseudorandom pseudorandom.cpp -lssl -lcrypto
方法1:遍历
1 |
|
方法2:Angr模拟
主要是看:https://blog.csdn.net/qq_43547885/article/details/113831507
脚本如下:
1 |
|
注:上述脚本不全,只是涉及了如何找出值,后续操作没跟上,我也懒得补上了。太懒了呀!
first
0x00 自己的解法
对程序进行分析,如下:


程序流程如下:(用python写出流程代码)
1 | # 1. 计算v10 |
start_routine()函数流程如下:(start_routine()函数中v2 = 4*i, i=0,1,2,3,4,5)
1 | sub_400E10(input[v4], 4, v8) |
尝试使用angr脚本解,但是一直有问题,脚本如下:
1 | def angr_solve(): |
0x01 大佬wp
题目链接:https://blog.csdn.net/weixin_45055269/article/details/106157485
python密码算法:https://www.cnblogs.com/wangyujian/p/11774027.html
总结了一下自己忽略的点:
(1)线程的启动是按时间顺序来的,这个时间是随机产生的。


(2)sub_400E10是一个MD5哈希函数。(没看出来竟然)
不理解的点:为什么自己的angr脚本不行。感觉还是得自己精进一下angr基础
大佬脚本如下:
1 | import hashlib |
因为不确定数组顺序,所以得试:(最终确定是juhuhfenlapsdunuhjifiuer)
1 | input1='juhuhfenlapsiuerhjifdunu' |
0x02 总结
其实感觉可以做出来,耐心!专注!
babydsp
在re-part-5中没做出来的题,由于wp也很少,所以还是得自己多琢磨。题目中有ClimbToTop.exe.16248.dmp与ClimbToTop.pdb。
0x00 自己的探索
想找dmp文件修复工具,未果。看到网上大都用windbg调试,本题目中还有ClimbToTop.pdb,所以感觉考察的是windbg的使用。
加载pdb文件,根据x ClimbToTop!*main*找到模块ClimbToTop!main模块,之后u ClimbToTop!main L30查看汇编命令,如下所示:

使用db 00007ff7 aefe7470查看上图绿框存的字符串,发现:

说明应该跳转到上图红框位置ClimbToTop!main+0x60 (00007ff7 aefe11a0)。

继续跳转到上述红框位置(原因与之前一样):00007ff7 aefe11ef。

上图中,第一个红框表示输出字符串:OK, if I don't messed up these heap, I can climb these hill。之后调用了两遍:
1 | DetourTransactionBegin |
最后两个红框代表程序走向,程序不应该走蓝框,因为蓝框输出字符串:LockResource ERROR。
下面逐步分析上述函数:
DetourTransactionBegin
1 | // DetourTransactionBegin |
分析DetourTransactionBegin,其逻辑如下:
1 | if (CurrentThreadId() == s_nPendingThreadId){ |
DetourUpdateThread
1 | // DetourUpdateThread |
其逻辑如下:
1 | if (operator_new != 0){ |
DetourAttach
1 | // DetourAttach |
意外发现
分析来分析去,发现DetourTransactionBegin等函数竟然是Microsoft Detours库中的函数…无语住了,搜了搜相关资料:
1 | Microsoft Detours 是一个 Windows 平台下的二进制重定向库,能够在运行时修改二进制程序的函数调用,实现函数钩子等操作。它是一个强大的工具,常用于动态调试、API Hooking、代码注入和病毒分析等领域。 |
一个Detours的例子如下,发现这个例子和我们的题目,是多么的契合!!
1 |
|
OK,那我们现在就要查找:(1)Detour钩取的函数是什么?(2)函数主代码是什么?
可以看到,Detour在attach阶段时,将pfnLockResource变成NewLockResource,然后主函数是一个_imp_LockResource。
1 | 补充: |
通过跟踪pfnLockResource,最终其指向了kernel32!_imp_LockResource。
1 | 补充: |
再跟踪NewLockResource,其代码如下:
1 | // NewLockResource |
1 | 00007ff7`aefe1080 4883ec28 sub rsp,28h |
程序崩溃点
使用.ecxr命令,查看程序崩溃点:
1 | rax=0000000000000040 rbx=0000000000004600 rcx=0000000000000040 |
使用!analyze -v,查看程序:

错误是由于程序段不可写造成的。
如何做
之后,打算用python重构NewLockResource。首先,将NewLockResource使用到的内存区域dump下来:.writemem data.bin 7ff7aefef0b0 7ff7 aeef 47b0。之后,写出NewLockResource对应的python脚本:
1 | #!/usr/bin/env python |
相当于对某段内存区域进行解密,然后将结果保存在data_decode.bin中。通过die.exe发现这是一个dll文件,使用ida打开,dllmain中发现函数,其中有:

可以确定,这就是我们要找的flag所在函数。
0x01 拿flag

经过对上述函数的分析,我们必须要知道输入的字符串序列,才能得出最后的flag。我们知道,dll加载到exe中会自动执行dllmain,虽然载入到file中的dll是加密的。所以下一步打算找一找crash文件中是否有字符串序列。
并没有查找到crash文件中的字符串,满足长度为192,且每个元素都小于等于0x31,且能生成合适的flag。解密后的dll也查找了,并没有找到。
0x02 其他人
网上的资料很少,并没有找到其他师傅的题解。难受。
maze

这是难度为5的题???感觉好简单。。
8*8的迷宫:
1 | ****** |
o为向右,O为向左,.为向上,0为向下。起点为左上角,终点为#。因此,flag为:nctf{o0oo00O000oooo..OO}
reverse_box
调试了很久,感觉不知道从何入手。它是一个程序,程序逻辑就是:输入字符串s,然后选取随机数r,对s+r进行一个加密,之后得到一个结果并输出16进制。无论输入的s是否是flag,它都会输出16进制的串?那??我应该怎么入手呢??
init与fini函数也看不出来啥来,里面的函数没发现有用的内容,而且没有找到SEH函数,似乎这不是ELF的内容。
0x00 其他大佬wp
我操了,攻防世界少了条件,条件是:95eeaf95ef94234999582f722f492f72b19a7aaf72e6e776b57aee722fe77ab5ad9aaeb156729676ae7a236d99b1df4a。flag格式:TWCTF{}。明天再看吧,服了。
调试了很久,有一个坑,就是:

上述红框是一个有符号数比较,其汇编指令为jns,所以写脚本的时候应该是0-127范围内的正数。
还有就是ror其实是循环移位。
最后上脚本:
1 | def alg(r): |
easygo
1400k的文件,有点小大。由于静态链接依赖的方法,最简单的 Go 二进制文件大小为数兆字节,而具有适当功能的二进制文件可以在 15-20mb范围内计算。
相关的Go逆向的博客,有事件可以看一下:https://www.anquanke.com/post/id/214940。
如果不用单独的插件,ida显示出来就一片混乱,有很多函数(因为静态链接)。之后使用go_parse的ida插件对程序进行解析,如下图所示:

上图红框为长度检查,黄框为内容检查,如果检查通过就输出success,否则输出fail。
动态调试发现长度为0x2A=42,且格式为flag{xxx}。之后程序在memqbody下断点,成功发现flag{92094daf-33c9-431e-a85a-8bfbd5df98ad}。

riskv-and-reward
risc_v:开源精简指令集,本题为risv_v 64位的ELF,感觉动调需要docker。
ida75不能直接加载,需要需要加载的需要新的loader:https://github.com/bingseclab/ida_riscv(不行),然后https://github.com/lcq2/riscv-ida(虽然支持ida7.x,但是只是32位的),但是也是只是静态调试。而ida7.7支持RISC_V。
然而,RISC-V的汇编并不好分析,函数名挺多而且都不知道是干啥的,而且不能转源代码(太菜咯)。所以打算用qemu(虚拟化软件,可以模拟多种硬件平台)动态调试。之前做babyArm(在re-part-5)中有搭建过qemu+ida的环境。
这个题搭完qemu+risc环境一运行直接出结果了,栓q。

polyre
发现是使用LLVM 7.0.1混淆进行处理后的ELF64。直接打开:

CFG可以的。还是先看一下OLLVM吧。想直接在memcmp上打断点查看,发现输入经过变换之后才进行比较,输入长度应该为0x30。找到一个脚本,链接如下:https://github.com/cq674350529/deflat,主要是用angr做符号执行来做去控制流平坦化,之后生成文件:

之后写脚本,先写正向脚本:
1 | inp = "".join(["98765432" for i in range(6)]) |
难点在于new_iter = (old_iter << 1) & 0xffffffffffffffff,一开始我总以为这样会失去信息。其实思考到后面,如果old_iter是奇数,那么就一定会走new_iter ^= 0xB0004B7679FA26B3,如果是偶数,就一定不会走上述语句。所以可以写解密脚本:
1 | targ = [0x96, 0x62, 0x53, 0x43, 0x6D, 0xF2, 0x8F, 0xBC, 0x16, 0xEE, 0x30, 0x05, 0x78, 0x00, 0x01, 0x52, 0xEC, 0x08, 0x5F, 0x93, 0xEA, 0xB5, 0xC0, 0x4D, 0x50, 0xF4, 0x53, 0xD8, 0xAF, 0x90, 0x2B, 0x34, 0x81, 0x36, 0x2C, 0xAA, 0xBC, 0x0E, 0x25, 0x8B, 0xE4, 0x8A, 0xC6, 0xA2, 0x81, 0x9F, 0x75, 0x55, 0xB3, 0x26, 0xFA, 0x79, 0x76, 0x4B, 0x00] |
补充:LLVM
相当于一个虚拟机。传统编译器架构:
1 | 源代码 |
LLVM架构:

1 | 1. 不同前端后端使用统一的中间代码LLVM Intermediate Representation (LLVM IR) |
LLVM混淆(LLVM Obfuscation,也叫OLLVM)是一种对LLVM IR进行变换的技术,旨在使生成的程序更难以阅读和分析。LLVM混淆技术可以应用于源代码、字节码、机器码等不同的层次。可以看一下博客:https://www.cnblogs.com/theseventhson/p/14861940.html
留言
- 文章链接: https://wd-2711.tech/
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明出处!