吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2263|回复: 13
上一主题 下一主题
收起左侧

[CTF] 2026春节解题领红包5 Windows中级题之Nuitka调试HOOK解题

  [复制链接]
跳转到指定楼层
楼主
max2012 发表于 2026-3-29 22:18 回帖奖励
本帖最后由 max2012 于 2026-4-2 16:36 编辑
  1. 用Exeinfo PE 0.0.8.8查看是Nuitka  onefile 打包的 python脚本

  2. 用 NuitkaExtractorPro和nuitkaExtractor解包, 都出现很多文件名第一个字母缺失

  3. 通过阅读Nuitka可知,不需要提取,直接获取运行时释放出的临时文件即可。

    另外也定位到了文件名缺失的原因

    没有开启_NUITKA_ONEFILE_TEMP_BOOL

    #define _NUITKA_ONEFILE_TEMP_BOOL 1

    多读了crc32字段,导致后续文件名都被吃掉 一个字母,只有第一个文件名正常

    #if _NUITKA_ONEFILE_TEMP_BOOL == 0
           uint32_t contained_file_checksum = readPayloadChecksumValue();
           uint32_t existing_file_checksum = getFileCRC32(target_path);
  4. 真正的脚本内容在dll,写个加载器方便动态注入

      // crackme_hard.dll
       HINSTANCE hGetProcIDDLL = LoadLibraryExW(
           dll_filename,
           NULL,
           LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
           LOAD_LIBRARY_SEARCH_SYSTEM32 |
           LOAD_LIBRARY_SEARCH_USER_DIRS
       );
    
           // 代码入口
       nuitka_dll_function_ptr nuitka_dll_function = (nuitka_dll_function_ptr) GetProcAddress(hGetProcIDDLL, "run_code");
    
           // 安装hook
       parseConstantsBlob(hGetProcIDDLL);
       hookLoadConstantsBlob(hGetProcIDDLL);
       hookNuitka_Function_New(hGetProcIDDLL);
    
           // 执行脚本功能代码
           result = nuitka_dll_function(argc, argv);

    结合Nuitka源码和IDA分析可确定hook入口地址

    // Nuitka_Function_New
    BYTE* ida_addr = (BYTE*) 0x313410170;
    // loadConstantsBlob
    BYTE* ida_addr = (BYTE*) 0x3133F0880;
  5. loadConstantsBlob中解析常量池的对象内容如下

    [HOOK] loadConstantsBlob called name:[__main__] count:83
    ====================== Dumping name:[__main__] count:[83] ==========================
    Address of array: 00007FFF63B78100
    Sizeof(array): 664 bytes
    ------+--------------------+--------------------+-------+---------------------
    Index | Address  (hex)     |   Value (ptr)      | Type  |   Value
    ------+--------------------+--------------------+-------+---------------------
       0 | 0x00007FFF63B78100 | 0x000002293FC2DBC0 |  list | [b'646321613b6062', b'11', b'63616367', b'2f', b'1965212128',
    b'0e', b'1f6226', b'0e', b'08626523', b'707070']
       1 | 0x00007FFF63B78108 | 0x000002293FC7D860 |   str | _parts
       2 | 0x00007FFF63B78110 | 0x00007FFF667DD3B8 |   int | 81
       3 | 0x00007FFF63B78118 | 0x000002293FC7D890 |   str | _key
       4 | 0x00007FFF63B78120 | 0x00007FFF667DCD58 |   int | 30
       5 | 0x00007FFF63B78128 | 0x000002293FD622B0 |   str | _total_len
       6 | 0x00007FFF63B78130 | 0x000002293FD643F0 |   str | 解密单个字符
       7 | 0x00007FFF63B78138 | 0x000002293FC7D8C0 |   str | current
       8 | 0x00007FFF63B78140 | 0x000002293FD622F0 |   str | _decrypt_char
       9 | 0x00007FFF63B78148 | 0x000002293FD64440 |   str | 获取指定位置的字符
      10 | 0x00007FFF63B78150 | 0x00007FFF667E9AE8 |   str | self
      11 | 0x00007FFF63B78158 | 0x000002293FD62330 |   str | _get_char_at_position
      12 | 0x00007FFF63B78160 | 0x000002293FD64490 |   str | 验证用户输入
      13 | 0x00007FFF63B78168 | 0x000002293FC7D8F0 |   str | total
      14 | 0x00007FFF63B78170 | 0x000002293FD644E0 |   str | 计算校验和
      15 | 0x00007FFF63B78178 | 0x00007FFF667E1D00 |   str | ''
      16 | 0x00007FFF63B78180 | 0x000002293FC7D920 |   str | flag
      17 | 0x00007FFF63B78188 | 0x000002293FD62370 |   str | checksum
      18 | 0x00007FFF63B78190 | 0x000002293FD64530 |   str | 获取目标校验和
      19 | 0x00007FFF63B78198 | 0x000002293FC7D950 |   str | hashlib
      20 | 0x00007FFF63B781A0 | 0x000002293FC7D980 |   str | sha256
      21 | 0x00007FFF63B781A8 | 0x00007FFF667E6628 |   str | encode
      22 | 0x00007FFF63B781B0 | 0x000002293FD623B0 |   str | hexdigest
      23 | 0x00007FFF63B781B8 | 0x000002293FC556C0 | slice | slice(None, 8, None)
      24 | 0x00007FFF63B781C0 | 0x00007FFF667DCB98 |   int | 16
      25 | 0x00007FFF63B781C8 | 0x000002293FD64580 |   str | 哈希函数
      26 | 0x00007FFF63B781D0 | 0x000002293FB9B190 |   int | 305419896
      27 | 0x00007FFF63B781D8 | 0x000002293FC7D9E0 |   int | 2882400001
      28 | 0x00007FFF63B781E0 | 0x000002293FB9B1B0 |   int | 1380994890
      29 | 0x00007FFF63B781E8 | 0x000002293FD623F0 |   str | hash_input
      30 | 0x00007FFF63B781F0 | 0x000002293FD645D0 |   str | 假检查
      31 | 0x00007FFF63B781F8 | 0x00007FFF666E8BF8 |   str | print
      32 | 0x00007FFF63B78200 | 0x000002293FC6FAF0 | tuple | (==================================================)
      33 | 0x00007FFF63B78208 | 0x000002293FC6FDC0 | tuple | (   CrackMe Challenge - Binary Edition)
      34 | 0x00007FFF63B78210 | 0x000002293FC7C3A0 | tuple | (Keywords: 52pojie, 2026, Happy New Year)
      35 | 0x00007FFF63B78218 | 0x000002293FC7C730 | tuple | (Hint: 1337 5p34k & 5ymb0l5!)
      36 | 0x00007FFF63B78220 | 0x000002293FC7DA20 | tuple | (      Try to decompile this in IDA!)
      37 | 0x00007FFF63B78228 | 0x000002293FC7DA50 | tuple | (--------------------------------------------------)
      38 | 0x00007FFF63B78230 | 0x000002293FD62430 |   str | CrackMeCore
      39 | 0x00007FFF63B78238 | 0x000002293FD64760 |   str |
    [?] Enter the password:
      40 | 0x00007FFF63B78240 | 0x000002293FD62470 |   str | fake_check
      41 | 0x00007FFF63B78248 | 0x000002293FC7DA80 | tuple | (
    [!] Close, but not quite there...)
      42 | 0x00007FFF63B78250 | 0x000002293FD624B0 |   str |
    Press Enter to exit...
      43 | 0x00007FFF63B78258 | 0x000002293FC7DAA0 |   str | verify
      44 | 0x00007FFF63B78260 | 0x000002293FD624F0 |   str | get_target_checksum
      45 | 0x00007FFF63B78268 | 0x000002293FC7DAE0 | tuple | (
    ==================================================)
      46 | 0x00007FFF63B78270 | 0x000002293FC7DB10 | tuple | (        *** SUCCESS! ***)
      47 | 0x00007FFF63B78278 | 0x000002293FC7DB40 | tuple | ([+] L33T H4X0R!)
      48 | 0x00007FFF63B78280 | 0x000002293FD62570 |   str | [+] Your answer:
      49 | 0x00007FFF63B78288 | 0x000002293FD64850 |   str |
    [!] Checksum mismatch:
      50 | 0x00007FFF63B78290 | 0x000002293FC7DB60 |   str |  !=
      51 | 0x00007FFF63B78298 | 0x000002293FC7DBA0 | tuple | (
    [X] Access Denied!)
      52 | 0x00007FFF63B782A0 | 0x000002293FC7DBD0 | tuple | ([X] Wrong password!)
      53 | 0x00007FFF63B782A8 | 0x000002293FD648A0 |   str | 主函数
      54 | 0x00007FFF63B782B0 | 0x00007FFF667E2A50 |   str | __doc__
      55 | 0x00007FFF63B782B8 | 0x00007FFF667E2B20 |   str | __file__
      56 | 0x00007FFF63B782C0 | 0x00007FFF666DEE80 |   str | __cached__
      57 | 0x00007FFF63B782C8 | 0x00007FFF667E23D8 |   str | __annotations__
      58 | 0x00007FFF63B782D0 | 0x00007FFF66702D78 |   str | sys
      59 | 0x00007FFF63B782D8 | 0x00007FFF667E34E0 |   str | __main__
      60 | 0x00007FFF63B782E0 | 0x00007FFF667E35B8 |   str | __module__
      61 | 0x00007FFF63B782E8 | 0x000002293FBAEC70 |   str | 核心验证类 - 将被编译成二进制
      62 | 0x00007FFF63B782F0 | 0x00007FFF667E39E0 |   str | __qualname__
      63 | 0x00007FFF63B782F8 | 0x00007FFF667E3090 |   str | __init__
      64 | 0x00007FFF63B78300 | 0x000002293FD62630 |   str | CrackMeCore.__init__
      65 | 0x00007FFF63B78308 | 0x000002293FD648F0 |   str | CrackMeCore._decrypt_char
      66 | 0x00007FFF63B78310 | 0x000002293FD64940 |   str | CrackMeCore._get_char_at_position
      67 | 0x00007FFF63B78318 | 0x000002293FD62670 |   str | CrackMeCore.verify
      68 | 0x00007FFF63B78320 | 0x000002293FD626B0 |   str | CrackMeCore.checksum
      69 | 0x00007FFF63B78328 | 0x000002293FD64990 |   str | CrackMeCore.get_target_checksum
      70 | 0x00007FFF63B78330 | 0x00007FFF666DC300 |   str | main
      71 | 0x00007FFF63B78338 | 0x000002293FC7DC00 | tuple | (
    
    [!] Interrupted)
      72 | 0x00007FFF63B78340 | 0x000002293FD62730 |   str | crackme_hard.py
      73 | 0x00007FFF63B78348 | 0x000002293FD62770 |   str | <module>
      74 | 0x00007FFF63B78350 | 0x000002293FC7DC30 | tuple | (self)
      75 | 0x00007FFF63B78358 | 0x000002293FC4F1F0 | tuple | (self, part_idx, char_idx, encrypted_byte)
      76 | 0x00007FFF63B78360 | 0x000002293FC736A0 | tuple | (self, pos, current, part_idx, part)
      77 | 0x00007FFF63B78368 | 0x000002293FD649F0 | tuple | (self, s, total, i, c)
      78 | 0x00007FFF63B78370 | 0x000002293FD62880 | tuple | (user_input, fake_hashes, user_hash)
      79 | 0x00007FFF63B78378 | 0x000002293FD62980 | tuple | (self, flag, i)
      80 | 0x00007FFF63B78380 | 0x000002293FC7DC60 | tuple | (s)
      81 | 0x00007FFF63B78388 | 0x000002293FC72930 | tuple | (core, user_input, cs, target)
      82 | 0x00007FFF63B78390 | 0x000002293FC729D0 | tuple | (self, user_input, i, expected)
    ------+--------------------+--------------------+-------+---------------------
  6. 在Nuitka_Function_New的hook代码中,对c_code安装hook

    static void* __fastcall fake_Nuitka_Function_New(
       function_impl_code_t c_code,
       PyObject *name,
       PyObject *qualname,
       PyCodeObject *code_object,
       PyObject *defaults,
       PyObject *kw_defaults,
       PyObject *annotations,
       PyObject *module,
       PyObject *doc,
       void **closure,
       Py_ssize_t closure_given)
    {
       void* result = g_pOriginal_Nuitka_Function_New(
           c_code, name, qualname, code_object,
           defaults, kw_defaults, annotations, module, doc,
           closure, closure_given
       );
    
       install_code_impl_hook(result, c_code);
    
       return result;
    }
  7. code_impl_hook 中 强制修改verify结果为True

    static PyObject* __fastcall fake_func_impl_code(PyThreadState *tstate,
           struct Nuitka_FunctionObject const *self, PyObject **python_pars)
    {
       const char* func_name=get_callable_name((PyObject *)self);
    
       PyObject* result = pOld_func_impl_code(tstate, self, python_pars);
    
       if ( !strcmp(func_name,"verify") && result==Py_False)
       {
           Py_XDECREF(result);
           result = Py_True;
           Py_INCREF(Py_True);
       }
    
       return result;
    }

    随便输入一个字符1

    ... ...
    [?] Enter the password:1
    [HOOK] fake_check:
    arg_0 (user_input):[1]
    [HOOK] hash_input:
    arg_0 (s):[1]
    [HOOK] hash_input return: [1803989619]
    [HOOK] fake_check return: [False]
    [HOOK] verify:
    arg_0 (self):[<__main__.CrackMeCore object at 0x000002294003ED20>]
    arg_1 (user_input):[1]
    [HOOK] verify return: [False]
    [HOOK] verify hack return: [True]
    [HOOK] checksum:
  8. 代码能继续走到checksum,能抓输出正确的password

    ... ...
    [HOOK] _decrypt_char return: [!]
    [HOOK] _get_char_at_position return: [!]
    [HOOK] _get_char_at_position:
    arg_0 (self):[<__main__.CrackMeCore object at 0x000002294003ED20>]
    arg_1 (pos):[29]
    [HOOK] _decrypt_char:
    arg_0 (self):[<__main__.CrackMeCore object at 0x000002294003ED20>]
    arg_1 (part_idx):[9]
    arg_2 (char_idx):[2]
    [HOOK] _decrypt_char return: [!]
    [HOOK] _get_char_at_position return: [!]
    [HOOK] checksum:
    arg_0 (self):[<__main__.CrackMeCore object at 0x000002294003ED20>]
    arg_1 (s):[52p0j13@2026~H4ppy_N3w_Y34r!!!]
    [HOOK] checksum return: [33753]
    [HOOK] get_target_checksum return: [33753]
    
    [!] Checksum mismatch: 49 != 33753
    
    Press Enter to exit...

    52p0j13@2026~H4ppy_N3w_Y34r!!!



免费评分

参与人数 7吾爱币 +7 热心值 +6 收起 理由
allspark + 1 + 1 用心讨论,共获提升!
gxfei888 + 1 + 1 我很赞同!
nanaqilin + 1 + 1 我很赞同!
rwang1 + 1 我很赞同!
358059103 + 1 + 1 我很赞同!
xianyu110 + 1 + 1 我很赞同!
努力加载中 + 1 + 1 热心回复!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
358059103 发表于 2026-3-30 10:07
本帖最后由 358059103 于 2026-3-30 10:15 编辑

终于等到Nuitka打包调试的教程,学习看看一下,感谢分享。还有一个问题,请教一下老师,这种Nuitka打包模式的,在X64dbg内能不能实现暴力pj呢,期待老师的回复
推荐
Hmily 发表于 2026-4-2 16:06
提个建议,可以把Nuitka 动调调试分析这样的字样加到标题里,这样可以方便后人搜索学习,帖子加精鼓励,期待更多分享。
3#
d199212 发表于 2026-3-30 08:46
4#
yksn233 发表于 2026-3-30 09:19
好厉害,感谢分享
5#
xcl 发表于 2026-3-30 09:27
牛啊,收藏了
6#
 楼主| max2012 发表于 2026-3-30 10:41 |楼主
358059103 发表于 2026-3-30 10:07
终于等到Nuitka打包调试的教程,学习看看一下,感谢分享。还有一个问题,请教一下老师,这种Nuitka打包模式 ...

理论上应该可以,把校验函数的返回值直接写死就可以。当前的hook就是暴力改内存获取结果的
7#
svip3122 发表于 2026-3-30 11:18
感谢楼主的分享 … …
8#
KinzerX 发表于 2026-3-30 15:33
学习一下大佬解题思路
9#
乔小风 发表于 2026-3-30 19:40

牛啊,收藏了
10#
5196 发表于 2026-3-31 08:32
厉害!学习了!!!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-4-21 20:03

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表