每日刷题系列

2024

7.17

[buu soullike]
1、之前有情况"stack frame is too big",ida分析栈帧时出现异常,这种属于去除花指令之类的出现的问题;而此题出现了function is too big,查看汇编也发现没什么问题,可能function确实这么大
在文件管理器中找到此文件
img
将functionmaxsize进行更改,将64改大一些,可以改为1024,只不过反编译的时候会慢很多,耐心等待
img
2、python中没有++的自增运算符,z3爆破贴加密代码的时候需要注意

7.18

[buu firmware]
1、路由器逆向,这么神奇的东西
参考wp https://blog.csdn.net/weixin_52369224/article/details/121219080
参考binwalk安装 https://blog.csdn.net/QQ1084283172/article/details/65441110
2、完整安装binwalk需要再ubuntu上进行,debian会缺少一些软件包(被折磨好久),之后可以选择wp中的方法,安装firmware-mod-kit来解压binwalk未解压成功的.squashfs文件
3、为此,我还重新换源,啥啥的,救命,换源方法: root打开etc/apt/sources.list
4、更换linux网络与主机网络一致方法: https://blog.csdn.net/lxy580/article/details/134423709
5、已经放弃了,debian装binwalk太麻法了,痛苦,就先大概知道有这样的路由器逆向的题目吧

7.19

[V&N2020 CSRe]
1、c#的混淆: Eazfuscator混淆,用die竟然识别不出来,看来要换一个die了
img
2、去除Eazfuscator混淆,de4dot工具

de4dot.exe "D:\xxx.exe"

7.20

[ciscn2023初赛 moveAside]
1、movfuscator混淆(一大堆mov mov mov)
参考文章: https://blog.csdn.net/CherestSan/article/details/117608664
[movfuscator][1]
混淆器: [1]:https://github.com/xoreaxeaxeax/movfuscator
混淆程序指令:movcc test.c -o test
[demovfuscator][2]
解混淆器: [2]:https://github.com/leetonidas/demovfuscator

7.21

DASCTF 2024暑期挑战赛
[Strangeprograme]
1、抽象,直接chef跑出来的十六进制转字符,明知道倒序了,之后发现有问号,以为最后几位的解密错了,就没交答案,吐了
在反调试的时候遇到is_debug,一个很好的办法,将所有调用is_debug的地方下断点,调试的时候将eax改为0
2、将加密逻辑动调,手搓一份,再解密即可

7.22

Deadsec
[flagchecker]
1、die和exeinfo都查不出pyinstaller但确实是用pyinstaller打包的,不能理解. 发现如果不是pyinstaller打包的解包时会报错"Missing cookie, unsupported pyinstaller version or not a pyinstaller archive",所以如果看到python,而且可以解包,就可以考虑这个文件是pyinstaller打包的了,还是太信赖die和exeinfo了
2、fork后,调试子程序
./linux_server -p 22222 //开个新端口
将fork后的程序patch为死循环,之后调试到fork后,开始运行父子进程
再打开一个ida,点击debugger,attach
img
之后将端口改为22222
img

7.23

WKCTF
[so_easy]
1.对于native题,下面这个文件的观赏性最好
img
2.CRC64效验,也是离谱,我就说这个加密好像哪里见过,但是再次看到,还是不会,害
先贴一下crc32校验吧

//查表形式
uint32_t crc32(const uint8_t *buf, size_t size, int32_t *crc32_tab){
    const uint8_t *p = buf;
    uint32_t crc = ~0U;
    while (size--){
        crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8);
    }
    return ~crc;
}

//不查表形式
uint32_t crc32(uint8_t* data, int size){
    uint32_t r = ~0;
    uint8_t *end = data + size;
    while (data < end){
        r ^= *data++;
        for (int i = 0; i < 8; ++i) {
            uint32_t t = ~((r&1) - 1);
            r = (r>>1) ^ (0xEDB88320 & t);
        }
    }
    return ~r;
}

真是不能理解这个加密形式,真太奇怪了,emo了,等我再修炼一段时间在研究吧,附上crc64解密脚本

secret = [0xBC8FF26D43536296, 0x520100780530EE16, 0x4DC0B5EA935F08EC,
        0x342B90AFD853F450, 0x8B250EBCAA2C3681, 0x55759F81A2C68AE4]
key = 0xB0004B7679FA26B3

flag = ""

# 产生CRC32查表法所用的表
for s in secret:
    for i in range(64):     #round
        sign = s & 1
        # 判断是否为负
        if sign == 1:
            s ^= key
        s //= 2
        # 防止负值除2, 溢出为正值
        if sign == 1:
            s |= 0x8000000000000000
    # 输出表
    print(hex(s))
    # 计算CRC64
    j = 0
    while j < 8:
        flag += chr(s&0xFF)
        s >>= 8
        j += 1
print(flag)

参考文章: https://forum.butian.net/share/1508
3、用z3爆破此题,我一开始的想法也是这样,但是没处理好,也没搞出来,真痛苦啊
what?也没人告诉我z3有自己的If函数啊,

If(condition, true_case, false_case)

错误示例:

from z3 import *

x = Int('x')
y = Int('y')

# 这种方式是错误的, 因为它是在运行时评估的, 而不是构建符号表达式
if x > y:
    result = x
else:
    result = y

# 创建求解器并添加约束
solver = Solver()
solver.add(x == 5, y == 3)

if solver.check() == sat:
    model = solver.model()
    print(f"x = {model[x]}, y = {model[y]}, result = {model.evaluate(result)}")
else:
    print("不可满足")

正确用法:

from z3 import *

# 创建整数变量
x = Int('x')
y = Int('y')

# 使用 Z3 的 If 函数构建条件表达式
result = If(x > y, x, y)

# 创建求解器并添加约束
solver = Solver()
solver.add(x == 5, y == 3)

if solver.check() == sat:
    model = solver.model()
    print(f"x = {model[x]}, y = {model[y]}, result = {model.evaluate(result)}")
else:
    print("不可满足")

附上此题的z3代码:

from z3 import *


chiper = [0x540A95F0C1BA81AE, 0xF8844E52E24A0314, 0x09FD988F98143EC9, 0x3FC00F01B405AD5E]
for i in range(4):
    v10 = BitVec('v10', 64)
    solver = z3.Solver()
    for j in range(255, 0, -5):
        v12 = (2 * v10) ^ 0x71234EA7D92996F5
        # if v10 >> 63 == 0:
        #     v12 = 2 * v10
        v12 = If(v10 >= 0, 2 * v10, v12)
        v13 = (2 * v12) ^ 0x71234EA7D92996F5
        # if v12 >> 63 == 0:
        #     v13 = 2 * v12
        v13 = If(v12 >= 0, 2 * v12, v13)
        v14 = (2 * v13) ^ 0x71234EA7D92996F5
        # if v13 >> 63 == 0:
        #     v14 = 2 * v13
        v14 = If(v13 >=0, 2 * v13, v14)
        v15 = (2 * v14) ^ 0x71234EA7D92996F5
        # if v14 >> 63 == 0:
        #     v15 = 2 * v14
        v15 = If(v14 >= 0, 2 * v14, v15)
        v10 = (2 * v15) ^ 0x71234EA7D92996F5
        # if v15 >> 63 == 0:
        #     v10 = 2 * v15
        v10 = If(v15 >= 0, 2 * v15, v10)
    solver.add(v10 == chiper[i])

    if solver.check() == z3.sat:
        print(solver.model())
    else:
        print("error")

7.24

RoarCTF2019
[polyre]
1、去除虚假控制流与平坦控制流: https://github.com/cq674350529/deflat
2、安装angr: https://www.cnblogs.com/level5uiharu/p/16925853.html
3、启动虚拟环境: source home/sy/angrfile/venv/bin/activate
4、Useage

Flat_control_flow useage: python3 deflat.py -f path/file_name --addr main_addr
Bogus_control_flow useage: python3 debogus.py -f pyth/file_name --addr main_addr

5、用d810去除混淆

7.25

2021羊城杯
[EasyVM] "angr解法"
1、已知flag的部分与size,进行约束 参考文章: https://www.cnblogs.com/61355ing/p/10523797.html

flag_chars = [claripy.BVS('flag_%d' % i, 8) for i in range(28)]
flag = claripy.Concat(*[claripy.BVV(b'flag{') + flag_chars] + claripy.BVV(b'}'))

2、并需要注意不让这28个字符中出现0x00或者'\n', 当然有其他的限制条件也可以一并加上去。

for k in flag_chars:
    st.solver.add(k != 0)
    st.solver.add(k != 10)

3、文章: https://34r7hm4n.me/0x401RevTrain-Tools/angr/11_利用angr符号执行梭哈VM类CTF赛题/
给了两个脚本,一个可以跑出来,另一个跑不出来,确实奇怪哈
不是,我flag都丢脸上了,也Fail?
img

7.26

[xor]
1、python的字符串转化成列表用法

cipher = "this_is_cipher"
flag = [(ord(list(cipher)[i]) ^ 0x30) for i in range(14)]

7.27

[ctf进阶指北]
1、what?学一年归来,仍是新生,乘法逆元解题???感觉基础知识差好多啊(怒了)
对于x * y = 1,则x与y互为乘法逆元
对于有限域中的元素 a, 它的乘法逆元记作 a^(-1), 满足以下条件:
a * a^(-1) = 1
以有限域 GF(p) 为例, 其中 p 是素数。在这样的有限域中, 对于任意非零元素 a, 它的乘法逆元
可以通过求解下面的方程来得到:
a * a^(-1) ≡ 1 (mod p)
这里的“mod p”表示对 p 取模。求解这个方程, 就能找到 a 的乘法逆元 a^(-1)。
a1为unsigned char*数组
a1[k]为有限域(0x00-0xff)

for(int i = 0;i < 12;i++)
{
    a1[i] = a[i] * 17 + 113;
}

如何求a1[i]呢,原a1[i] * 17等于a1[i] - 113则求出17在256下的乘法逆元ss,再用(a1[i] - 113) * ss就等于原a1[i] * 17 * ss就等于a1[i]
17在mod 256下的逆元是241

for(int i = 0;i < 12;i++){
    a1[i] = (a[i] - 113) * 241
}

而为什么不能直接a1[i] = (a1[i] - 113) / 17则是因为可能会在a1[i] * 17时产生溢出,导致数据损失.
2、哎,怒了,真遇到了,用z3取余应该可以解出来啊......知道可能会溢出,但是一直不知道怎么写脚本

salt = [21, 24, 215, 9, 183, 232, 62, 241, 194, 18, 65, 50, 67, 150, 206, 250,
255, 224, 213, 19, 22, 140, 103, 11, 248, 106, 243, 5, 121, 184, 211, 77, 224,
74, 149, 228, 68, 113, 180, 26, 151, 241, 122, 177, 0]
target = [58, 123, 72, 156, 80, 41, 69, 186, 53, 70, 205, 115, 21, 195, 28,
247, 171, 85, 243, 183, 193, 161, 110, 209, 71, 132, 238, 189, 99, 105, 179,
193, 37, 16, 105, 37, 218, 173, 177, 193, 85, 199, 251, 254, 0]
S = b""
for i in range(0, 44, 4):
    T = (target[i] << 24) | (target[i+1] << 16) | (target[i+2] << 8) |target[i+3]
    B = (salt[i] << 24) | (salt[i+1] << 16) | (salt[i+2] << 8) | salt[i+3]
    # A * 0x01919811 + B == T

    A = (T - B) * pow(0x01919811, -1, 2**32) % 2**32
    S += A.to_bytes(4, "big")
    print(S)

这里面的pow(0x01919811, -1, 2**32)就是求逆元,然后用A.to_bytes(4, "big")以大端序转化成字节串(题目比较特殊,是大端序).

7.28

[buu findkey]
1、大胆写一写,总是觉得好像哪里有问题,就不敢写........,明明很简单的,害

7.29

[moe dynamic]
1、之前64位的dll与32位的dll不会补,好像补错了几个位置,现在也不会报错了,而是直接运行不了,还好我最终还是发现了问题所在
img
之后重新安装补一下dll就行.

7.30

[moe moedaily]
1、很新颖的题目,excel/xlsx逆向?加密逻辑以每步的值与excel函数存在第二张secret表中表示.此题是tea加密

7.31

[moe Bomb Defusion]
1、第一次遇到whl逆向,真好神奇,记录一下方法吧,whl是第三方库的组合,可以将自己的py文件,或者py文件打包的pyd文件打包在一起,用pip install xxx.whl就可以安装,注意whl的名称中一般会包含python适用的版本,可以选择创建一个虚拟环境安装whl.
2、将whl当成压缩包解压,如果有py文件源码,那太好了,但是一般为了防止反编译一般会选择将源码打包为pyd文件,网上有一篇pyd的逆向,看着好难....... https://bbs.kanxue.com/thread-259124.htm
3、在安装好whl后,调用help(xxx)可以查询到库函数的一些基本信息,之后根据信息,使用库函数,进行逆向
4、可以将解压缩的pyd文件放到ida中查看,可以看到一些字符串信息,可以提供帮助.

8.1

[moe d0tN3t]
1、我勒个c#啊,多用dnspy吧,net_reflector又不知道抽什么风......

2025

3.3[6358]

  1. ENIGMA脱壳,尝试了xvlk,部分完成了恢复
  2. Enigma Protector非开源,官网下载后导入exe进行加壳
  3. 较新的Enigma Protector脱壳文章: https://bbs.kanxue.com/thread-268825.htm
  4. 感觉ctf中很少会考商用壳,先搁置

3.9[766]

  1. CRC64解密
    secret = [0x32e9a65483cc9671, 0xec92a986a4af329c, 0x96c8259bc2ac4673,
            0x74bf5dca4423530f, 0x59d78ef8fdcbfab1, 0xa65257e5b13942b1]
    key = 0xb1234b7679fc4b3d
    
    flag = ""
    
    # 产生CRC32查表法所用的表
    for s in secret:
        for i in range(64):
            sign = s & 1
            # 判断是否为负
            if sign == 1:
                s ^= key
            s //= 2
            # 防止负值除2,溢出为正值
            if sign == 1:
                s |= 0x8000000000000000
        # 输出表
        print(hex(s))
        # 计算CRC64
        j = 0
        while j < 8:
            flag += chr(s&0xFF)
            s >>= 8
            j += 1
    print(flag)
    

3.10[400]

base knowledge

  1. windows动态库,导入库,静态库

    • 静态库: 将函数和数据编译进一个二进制文件(扩展名.lib),使用静态库时,编译可执行文件会复制其中的函数和数据,并将他们和应用程序的其他模块组合起来创建最终的可执行文件.
    • 动态库: 一般的动态库会有(.lib与.dll)两个文件,导入库文件(.lib)包含该DLL导出的函数和变量的符号名,而.dll文件包含该DLL实际的函数和数据。
  2. __stdcall 与 __cdecl

    __stdcall被调用者自动清理堆栈

    __cdecl调用者手动清理堆栈

  3. 调用dll库中函数(针对winx64)

    #include <iostream>
    #include <windows.h>
    
    using namespace std;
    
    typedef int (__cdecl *FnHowToUse)(int);
    
    int main() {
        HMODULE hDLL = LoadLibraryA("howtouse.dll");
        if(hDLL){
            FnHowToUse fn = (FnHowToUse)GetProcAddress(hDLL, "fnhowtouse");
            if (!fn) {
                cerr << "无法找到函数 fnhowtouse" << endl;
                FreeLibrary(hDLL);
                return 1;
            }
            int result = fn(42);
            cout << "fnhowtouse(42) 返回值: " << result << endl;
        } else{
            cerr << "无法加载 DLL" << endl;
            return 1;
        }
        FreeLibrary(hDLL);
        return 0;
    }
    
  4. 框架指针省略(Frame Pointer Omission)(FPO)
    大体意思:不再将ebx的值压栈,用mov ebp esp去用ebp保存上一个函数ebp的值,而是不修改ebp,单纯以esp对参数和局部变量进行寻址
    参考文章:https://www.cnblogs.com/awpatp/archive/2009/11/04/1595988.html

dll逆向

  1. 调用顺序

     DllEntryPoint()
     __DllMainCRTStartup()
     _pre_c_init()    _CRT_INIT()   DllMain()
    
  2. 特殊函数

    • atexit: 会指定dll退出的回调函数,可以在此进行某些处理

3.11[3328]

base knowledge

  1. 结构化异常处理SEH(Struct Exception Handle)
    • __try{}/__finally{}和__try{}/__except{}结构本质上是对Windows提供的SEH的封装。
    • try/except框架
    __try{
    
    //被保护的代码块
        ……
    }
    
    __except(except fileter/*异常过滤程序*/){
        //异常处理程序
    }
    
    其中过滤程序except fileter可以是一个简单的表达式或一个函数(返回值应为EXCEPTION_CONTINUE_SEARCH、EXCEPT_CONTINUE_EXECUTE或EXCEPT_EXECUTE_HANDLER之一)
    img
    例如except fileter可以规定除0异常进行下面异常处理,如果出现的异常非除0异常会被抛向更高层处理.

逆向tips

  1. except fileter可能会有类似函数
    _BOOL8 __fastcall sub_7FF7C6E01000(int a1)
    {
    return a1 == 0xC0000094;
    }
    
    这里面0xC0000094为除以0异常代码,依次可以判断异常问题.
  2. 如果看到main函数旁边有此单独的代码段
    img
    就可以很快发现程序中有SEH.
  3. 对于MSVC编译的c++异常处理可以直接由ida decompile.
    参考文章: https://www.cnblogs.com/yilang/p/11233935.html
    https://www.cnblogs.com/yilang/p/11238201.html

3.12[3848]

  1. 只要看到单独出来的小块,没有__except_fliter字样,并且没有反编译出try/catch,就很有可能是g++编译的异常处理
    img

3.13

  1. 使用z3处理ida识别的加密时,使用Bitvec时,需要注意溢出

3.14[614]

  1. pyc.encrypted解密
    img
    • 在main.exe_extracted中找到pyimod00_crypto_key.pyc,在此文件中找到key
    • 以下面代码进行解密
      import tinyaes
      import zlib
      
      CRYPT_BLOCK_SIZE = 16
      
      # 填入密钥
      key = bytes('f8c0870eba862579', 'utf-8')    # f8c0870eba862579是在pyimod00_crypto_key.pyc中得到的key
      
      inf = open('check.pyc.encrypted', 'rb')  # 打开加密文件
      outf = open('check.pyc', 'wb')  # 输出文件
      iv = inf.read(CRYPT_BLOCK_SIZE)
      
      cipher = tinyaes.AES(key, iv)
      plaintext = zlib.decompress(cipher.CTR_xcrypt_buffer(inf.read()))
      outf.write(b'\x42\x0d\x0d\x0a\0\0\0\0\0\0\0\0\0\0\0\0')# 文件头,取 struct.pyc 的前 16 个字节
      outf.write(plaintext)
      
      inf.close()
      outf.close()
      

3.15

  1. rust逆向基础

3.16

Eidt struct

  1. 今日刷题遇到一个与结构体相关的题目,总结逆向经验看到类似下面的代码要考虑是一个结构体,用系统调用函数判断是什么结构体
    img
  2. 注意Ida的local tpye的对应结构体有可能并不正确(也有可能是此题出题人的问题)
    img
    这里给的是_KPROCESS但是通过下面函数调用可以知道Process是一个Eprocess结构体

    PsLookupProcessByProcessId((HANDLE)0xE6C, &Process);

  3. 记录一下windows的结构体库: https://www.vergiliusproject.com/kernels/x86

微信小程序逆向

  1. wxappUnpacker安装与使用: https://github.com/Fickley/wxappUnpacker
  • wxappUnpacker可以对.wxapkg进行解包,得到程序源码
  1. 暂时先用工具(wxapkg)代替,如遇到工具不能处理的情况,再学习1中方法
  • 使用方法: 将__APP__.wxapkg拖到wxapkg.exe上执行,执行后当前目录会出现__APP__.wxapkg_unpack文件夹,使用webstorm作为项目打开即可.

3.20

  1. txz 文件是一种 tar + xz 压缩格式,表示使用 tar 归档文件后,再用 xz 压缩。常见于 Linux 系统,类似于 .tar.gz (.tgz) 但压缩率更高。(可以直接用7zip解压)

3.25

  1. pyc文件,在执行python后,会存放在\Lib\site-packages\__pycache__中
  2. 修复pyc文件,可以考虑生成相同版本的pyc文件,用前16字节修复(如果有struct.pyc等可以直接使用)
    pyc文件结构: https://wzt.ac.cn/2019/02/13/pyc-simple/

3.28

  1. 逆向技巧: 解密出一串字符,可以尝试放入随波逐流一键解码尝试一下.
posted @ 2025-07-07 17:48  Un1corn  阅读(60)  评论(0)    收藏  举报