180626 逆向-SUCTF(Python大法好)
時隔許久詳細的復現一下~
這個題目也挺有意思的,刺激學了一遍pyc233
題目提供了一份opcode.txt、elf二進位制程式a和一個密文cipher.txt
opcode開啟來可以發現是pyc的解析
雖然有code,但是試著用python解析了一下發現有點複雜
讀opcode是不可能的,這輩子都不可能的
本來讀起來就麻煩,缺少符號資訊就更恐怖了,更別說還有lambda和join等等騷方法了
思路轉為根據一些關鍵詞來搜尋,試圖找到該檔案的生成方法和逆轉換方法。畢竟只要能得到pyc就能通過uncompyle的工具還原出原始碼
搜了一下找到了幾乎完全一樣的指令碼
然後拿一個正常的pyc打了一份解析出來,對照發現除了code的disassembly以外什麼都不缺,這也就意味著根據上述資訊是可以還原出pyc的
比賽的時候是手動搞的,懶得寫指令碼操作了,本來都不熟悉再出什麼bug調起來更慢2333
pyc整體是4位元組版本標識+4位元組時間戳+一個PyCodeObject。PyCodeObject的內部由若干成員組成。
每個成員的第一個位元組是型別標識,然後四個位元組表示長度,接著依次列舉內部的各個成員
型別標識如下
#define TYPE_NULL '0'
#define TYPE_NONE 'N'
#define TYPE_FALSE 'F'
#define TYPE_TRUE 'T'
#define TYPE_STOPITER 'S'
#define TYPE_ELLIPSIS '.'
#define TYPE_INT 'i'
#define TYPE_INT64 'I'
#define TYPE_FLOAT 'f'
#define TYPE_BINARY_FLOAT 'g'
#define TYPE_COMPLEX 'x'
#define TYPE_BINARY_COMPLEX 'y'
#define TYPE_LONG 'l'
#define TYPE_STRING 's'
#define TYPE_INTERNED 't'
#define TYPE_STRINGREF 'R'
#define TYPE_TUPLE '('
#define TYPE_LIST '['
#define TYPE_DICT '{'
#define TYPE_CODE 'c'
#define TYPE_UNICODE 'u'
#define TYPE_UNKNOWN '?'
#define TYPE_SET '<'
#define TYPE_FROZENSET '>'
PyCodeObject的型別識別符號是’c’,即0x63
接下來依次是4個引數,argcount, nlocals, stacksize, flags,每個引數4位元組小端序表示
然後是co_code,即opcode的位元組流,作為一個string儲存。型別識別符號為’s’,即0x73
string顯然需要len來標識接下來的讀取範圍,因此4位元組表示len,後面len個位元組就是bytes啦
再往後是consts常量,它是一個tuple。型別識別符號為’(‘,0x28。後面4位元組表示tuple的len,即元素個數。然後是依次放置各個元素,通常情況下最大PyCodeObject的consts裡還會有PyCodeObject,是一個遞迴的過程。依次向內解析即可。除此以外還會有None(只需要型別識別符號’N’即可,無長度無內容)、Int(型別識別符號‘I’+4位元組值)、String(如前所述,型別識別符號’s’+len+content)等等
consts之後是names、varnames、freevars、cellvars四個tuple,空的tuple長度為0即可,否則字串照樣展開就行
然後是filename和name兩個string、firstlineno這個四位元組表示的常量(不需要型別標識和長度)以及最後一個string,lnotab
全部輸入以後通過marshal即可裝載,uncompyle系工具就可以成功將其反編譯了
明天寫個自動化的工具來遞迴還原~
得到py後發現其將key轉為hex後直接通過cdll.LoadLibrary呼叫函式……所以我折騰這麼半天就是為了得到它是把key轉hex的結論?!
逆向二進位制程式,發現其中的加密方法比較眼熟,其實就是RC4
流密碼沒什麼攻擊方法,只能爆破金鑰了
根據*號長度猜測key是8位,從最簡單的純數字入手
多執行緒爆破,啟動!
單執行緒爆了很久都沒反應,多執行緒倒是秒出(:з」∠)運氣真好