iT邦幫忙

2024 iThome 鐵人賽

DAY 29
0
Security

picoCTF 刷題分享系列 第 29

picoCTF 刷題分享---Day 29(python dis module理論補足)

  • 分享至 

  • xImage
  •  

昨天的標題忘了改了,就簡單叫做個Crackme 0x001吧,今天再來到下一題


題目:weirdSnake

Download and try to reverse the python bytecode.
https://docs.python.org/3/library/dis.html

  • 下載完檔案後會看到個鬼東東
  • 在看到hint後,可以知道他是python的bytecode
  • 我的第一感覺是,應該有某種軟體可以直接執行,但我想要自己來
  • 所以開始了一步錯步步錯了🫠🫠
  • 首先會看到1 0 LOAD_CONST 0 (4)
    • 1:在原本的程式碼裡的第幾行
    • 0:是該指令在整個函數中的位置,也就是該指令的行號或偏移量
    • LOAD_CONST:從常量池中加載數值,如數字、字串等
      • 常見的有以下幾種指令
        • LOAD_CONST:從常量池中加載數值,如數字、字串等到堆疊。
        • LOAD_NAME:從當前的命名空間(全局或局部)加載變數到堆疊。
        • STORE_NAME:將值存入變數。
        • BINARY_ADD:進行加法運算。
        • COMPARE_OP:進行比較操作,例如 <, >, == 等。
        • CALL_FUNCTION:調用函數。
        • BUILD_LIST:用於建立清單(list)的指令。BUILD_LIST 40 表示創建一個包含 40 個元素的列表。
        • POP_JUMP_IF_FALSE:如果條件為假,則跳轉到指定位置。這在流程控制中如 if 判斷裡常見。
        • GET_ITER 和 FOR_ITER:用來進行迴圈操作。GET_ITER 獲取一個迭代器,而 FOR_ITER 則控制迴圈進行。
    • 0:常量池裡的索引值(常量池[0]
    • (4):值(把4 push into stack
  • 所以簡單來說從0到78行就是把40個值推入堆疊裡
  • 第80行是建立個空間為40的list
  • 第82行是把值存到名為input_list的串列裡
  • 所以到第82行以前,可以說在做:input_list = [4,51,41,...,78]:
    https://ithelp.ithome.com.tw/upload/images/20241013/20164155JtDEhh4vxC.png
  • 再來要到接下來的:
    https://ithelp.ithome.com.tw/upload/images/20241013/20164155dwCvH4EIzO.png
  • 這代表先把'J'推入堆疊裡
  • 再把'J'pop出來並存到名為key_str的變數裡
    https://ithelp.ithome.com.tw/upload/images/20241013/201641550CKgkdSPxZ.png
  • 再來這裡要注意喔!!
  • 首先把'_'推入堆疊
  • 再把key_str推入堆疊
  • 這時我們的堆疊會長:top:key_str:'J',bottom:'_'
  • 這時,做了一個binary_add的動作把兩個相加,這時先pop出來的要在後面
  • 所以binary_add會變成:'_'+'J',所以是'_J'不是'J_'喔!
  • 再換到下一個block
    https://ithelp.ithome.com.tw/upload/images/20241013/201641551N6kP3UH4L.png
  • 加速囉
  • 先push key_str再push 'o'
  • 做BINARY_ADD:'_Jo'
  • 再存回去變數裡key_str = '_Jo'
  • 以此類推會得到key_str = 't_Jo3'
  • (我不知道大家的一不一樣啦
    https://ithelp.ithome.com.tw/upload/images/20241013/20164155lmPh276N96.png
  • 這裡的<listcomp>全名是list comprehension
  • 長這樣:[i for i in range(n)] or [i for i in Iterable_item]
  • 他先創造一個<\listcomp>再推入堆疊
  • 再把key_str推入stack
  • GET_ITER介紹:
    • 轉換為迭代器:當遇到需要對一個集合(例如 list 或 string)進行迭代的情況時,它會先將該集合轉換成一個可迭代對象(迭代器)
    • 迭代使用:一旦有了迭代器,Python 可以使用它來遍歷集合中的元素,這裡使用CALL_FUNCTION去呼叫剛剛存的<listcomp>
  • 會得到['t','_','J','o','3'],再回存回Key_list
    https://ithelp.ithome.com.tw/upload/images/20241013/20164155cq1gKckIcm.png
  • 接下來的134行是把內建函式len()推入堆疊,待會要用
  • 再來推入key_list,再call_func計算key_list的長度(len(call_func))(得到5,並存入堆疊
  • 對input_list做一樣的事情,會得到40,並存入堆疊
  • 所以現在堆疊裡的情況為:top:40,bottom:5
  • 再來做比較pop 40 and 5 比較小於所以會變成 => 5 < 40(記住先pop出來的要放右邊
  • 如果不符合跳到162行(這裡符合所以不跳轉
  • 繼續看150行
    https://ithelp.ithome.com.tw/upload/images/20241013/20164155oqV5KQm3bi.png
  • 這裡可以看到extend這個內建函式適用於兩個字串相加時所使用的
    • 可以補充她跟append的差異:
      • list.append(element)# 裡面只能是單一元素
      • list.extend(list2)# 可以字串相加
  • 相加完後會看到JUMP_ABSOLUTE 134
  • 跳到134行重新比較長度,所以可以知道
  • 當跳到162時,key_list會等於['t','_','J','o','3']*8(如圖:
    https://ithelp.ithome.com.tw/upload/images/20241013/20164155y2sDGIOXPg.png

https://ithelp.ithome.com.tw/upload/images/20241013/20164155xjZGCJhxnb.png

  • 這裡我在看的時候怕看錯有畫圖,按造順序存入堆疊:
  • listcomp -> zip -> input_list -> key_list
  • 所以當第一次call_func時會執行的是:zip(input_list,key_list)
  • zip([1,2,3],[a,b,c]) => [(1,a),(2,b),(3,c)]
  • 所以這裡會得到:[(4,'t'),(54,'_'),(41,'J'),(0,'o'),(112,'3'),...,(78,'3')]
  • GET_ITER對其轉成可迭代物件
  • call_func會把他變成<listcomp>,這裡要看到他給的listcomp定義:
    https://ithelp.ithome.com.tw/upload/images/20241013/20164155kVuzyxfIUI.png
  • 他今天是先STORE_FAST a 再 STORE_FAST b(這裡的STORE_FAST跟STORE_NAME其實沒差,只是存取的變數是全域(NAME)還是區域變數(FAST)(是因為存取速度關係而命名的
  • push a 再 push b
  • 執行BINARY_XOR,所以這裡pop的時候b會在右邊 => a ^ b
  • 而我們的b 是['t','_','J','o','3'],所以會變成 a^ord(b)
  • 180行,把結果存入result裡面
  • result = [4^ord('t') = 4 ^ 116 = 112,
    (54, '') -> 54 ^ ord('') = 54 ^ 95 = 105,
    (41, 'J') -> 41 ^ ord('J') = 41 ^ 74 = 99,...]
  • result = [112,105,99...]
    https://ithelp.ithome.com.tw/upload/images/20241013/20164155LhRUGvzj1Q.png
  • 加油到最後了!!!!!!
  • push ''
  • push join
  • push map
  • push chr
  • push result
  • 現在stack長這樣:
  • top -> result -> chr -> map -> join -> '' -> bottom
  • 所以慢慢來(雖然我只剩20分鐘了
  • 第一步:把result轉成文字:map(chr,result)
  • 把map連接成文字(使用''.join(map(chr,result))
  • 把結果存到result_text
  • 把它寫成程式碼:
    https://ithelp.ithome.com.tw/upload/images/20241013/20164155sCfiOOAhOA.png
  • 就會得到我們的flag啦!!
  • 格式:picoCTF{flag.content}

後記:
夭壽還有一天好可怕,今天寫了5000多個字,我今天寫的比較詳細,我之後會統整一下,放到我的github等我有空一點的時候(嘿嘿,我要去睡覺了,各位晚安啦


上一篇
picoCTF 刷題分享---Day 28(組語理論補足)
下一篇
picoCTF 刷題分享---Day 30(賽後心得)
系列文
picoCTF 刷題分享30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言