CPython逆向實戰分析

蚁景网安实验室發表於2024-10-25

Python程式碼轉換為C程式碼的時候,將會大大增加框架程式碼量。

基礎教程 | Cython 官方文件中文版(gitbooks.io)

1、正向py->c

先有正向,再有逆向

pip install cython

寫一個簡單的pyx檔案

.pyx 檔案是由 Cython 程式語言 "編寫" 而成的 Python 擴充套件模組原始碼檔案

print("hello")

寫一個 setup.py檔案

from distutils.core import setup
from Cython.Build import cythonize
​
setup(
    ext_modules = cythonize("test.pyx")
)

使用命令開始編譯

python setup.py build_ext --inplace

image

生成如下檔案

image

開啟test.c發現有幾千行程式碼

image

單純的一行python程式碼,生成為c程式碼就幾千行

呼叫so檔案

image

2、逆向分析

2.1 字串型別

_Pyx_CreateStringTabAndInitStrings

全域性字串賦值一般在_Pyx_CreateStringTabAndInitStrings​中,該函式中使用的字串定義陣列形如:

typedef struct {
    PyObject **p;
    const char *s;
    const Py_ssize_t n;
    const char* encoding;
    const char is_unicode;
    const char is_str;
    const char intern;
} __Pyx_StringTabEntry;

而字串是透過__Pyx_StringTabEntry​的陣列進行初始化的,也就是說當我們在該函式中看到以下虛擬碼時:

v8 = _mm_unpacklo_epi64(&qword_28A98, "AttributeError");
v9 = 15LL;
v10 = 0LL;
v11 = 0x100;
v12 = 1;

就代表這是一個{&qword_28A98, "AttributeError", 15, 0, 1, 0, 1}​的__Pyx_StringTabEntry​,也就是說qword_28A98​中將要初始化一個內容是"AttributeError"​的字串物件的地址,在後續呼叫中,呼叫到AttributeError字串的地方都會用&qword_28A98​指代

【----幫助網安學習,以下所有學習資料免費領!加vx:dctintin,備註 “部落格園” 獲取!】

 ① 網安學習成長路徑思維導圖
 ② 60+網安經典常用工具包
 ③ 100+SRC漏洞分析報告
 ④ 150+網安攻防實戰技術電子書
 ⑤ 最權威CISSP 認證考試指南+題庫
 ⑥ 超1800頁CTF實戰技巧手冊
 ⑦ 最新網安大廠面試題合集(含答案)
 ⑧ APP客戶端安全檢測指南(安卓+IOS)

2.2 整數型別

_pyx_pymod_exec_chal

qword_29170 = PyLong_FromLong(113LL, v9, v244, v245);
if ( qword_29170 )

qword_29170​中將儲存一個值為113​的整數型別的Python物件。

qword_29600 = PyLong_FromString("2654435769", 0LL, 0LL);
if ( qword_29600 )

大數會用PyLong_FromString​函式來初始化,這裡qword_29600​中將儲存一個值為2654435769​的整數型別的Python物件,後續用到2654435769的地方將使用qword_29600​。

2.3 import寫法

v539 = _Pyx_ImportDottedModule_constprop_0(random);
if ( PyDict_SetItem(_pyx_mstate_global_static, random, v539) < 0 )
{

匯入``random``模組,同``import random

3、實戰分析

這裡提供一道自己出的題目,採用了RC4加密,流程很簡單。

讓我們開幹

image

把提供的so檔案拖進IDA中

image

而且這個函式 _Pyx_CreateStringTabAndInitStrings() 非常大,不能反編譯

目前不知道這個函式的加密,我們先列印其相關的屬性,看看能不能找到蛛絲馬跡

import test
dir(test)

image

發現是RC4加密,這樣邏輯就清晰了

所以現在的目標是獲得RC4的秘鑰和密文咯,假設RC4沒有魔改

剛才我們在函式_Pyx_CreateStringTabAndInitStrings 找到了非常類似密文的值

9d7422eabf8baf369c09121f02e940099d9c6b538d88e30aac08

但是沒有找到 秘鑰,說明秘鑰可能就不是字串,而是byte型別!

我們先搜尋RC4相關函式

image

image

發現程式碼非常多,暫時先不去分析RC4演算法

看看哪裡呼叫了我們的RC4演算法

image

函式:_pyx_pymod_exec_test

image

但是byte型別怎麼初始化呢?

我們編寫一個demo,然後反編譯去檢視初始化方式即可

demo.pyx

key = b'mykekekeke'
en_flag = b'12312312312312'

demo_setup.pyx

from distutils.core import setup
from Cython.Build import cythonize
​
setup(
    ext_modules = cythonize("demo.pyx")
)

執行命令

python demo_setup.py build_ext --inplace

先看看c檔案

image

還是很清晰的,直接IDA分析so檔案

image

發現byte型別也儲存在函式_Pyx_CreateStringTabAndInitStrings

所以我們再翻閱一下,成功找到類似key的程式碼

image

DASCTF{cpython_is_so_easy}

image

更多網安技能的線上實操練習,請點選這裡>>

相關文章