首页
社区
课程
招聘
10
[原创] 2025吾愛解題領紅包活動(Android題解)
发表于: 2025-2-13 10:00 25898

[原创] 2025吾愛解題領紅包活動(Android題解)

2025-2-13 10:00
25898

簡單寫一下Android部份的解題思路。

明顯的xxtea特徵。

解密後直接得到flag

目標是找到秘鑰。

Java層關鍵邏輯如下,調用了Check函數來檢查密鑰。

是個native函數。

嘗試直接hook RegisterNatives,發現Check果然是動態注冊的,在0xe8c54

Check一開始是一些反調試邏輯。

先看anti1,它調用decrypt_str解密字符串,但奇怪的是解密出來的字符串不是以\x00結尾,導致opendir直接失敗,使得後面的反調試邏輯形同虛設?( 不知是故意的還是不小心的 )

anti2do_something1也同理,皆因為decrypt_str的問題導致後續的邏輯失效。

繼續向下跟,看到它動態計算出一個函數地址,大概率就是加密函數,最後與密文進行對比。

一開始以為動態計算的那個函數地址是固定的,後來才發現有兩個不同的地址,會隨著上面anti1anti2do_something1getenv等函數返回的結果而改變。

類似蜜罐的概念,當觸發anti邏輯後,不主動殺死APP,而是改變程序的執行流,導向錯誤的分支。

func1func2如下,前者是錯誤的分支,後者是正確的,我的環境默認會走func1

可以看到兩者的加密方式都是相同的異或加密,不同的只有異或的值。

經測試發現,手動hook getenvdo_something1修改其參數、返回值後,程序才會走向func2。這時再hook encrypt,將正確的異或值dump下來。

最終解密腳本:

輸出:flag: flag{md5(uid+2025)}

先看看題目描述,要幾個重點:

再看看APP,要求輸入UID和Flag。

用新版jeb查看Java層邏輯( Java層有混淆,jeb能忽略部份混淆,方便分析 ),發現調用check函數來檢查,參考分別是UID和Flag。

check是Native函數。

native層的check是靜態注冊的,能直接搜到。

繼續深入分析( 配合動調來遂一分析每個函數的作用 )。

init_some_data函數如下,結合後面的分析可以知道,這裡是在初始化vm虛擬機的opcodes,存放在a1[0xC000 ~ 0xC200]

a1記為vm_ctx,意指vm虛擬機的上下文空間。

初始化完成後便會調用start_vm正式啟動虛擬機進行計算。

一開始會通過一些運算獲取_opcodearg,前者是操作碼、後者是一些固定的參數( 在不同的操作碼中都有不同的含義 )。

接著就是vm最經典的一大段switch,每個case對應不同的handler,實現了不同的功能。

每個handler裡基本上都會用到vm_ctx[0x10002],一些參數、中間值、計算結果都會存放在vm_ctx[0x10002]指向的位置。

而且可以看到vm_ctx[0x10002] + 4vm_ctx[0x10002] - 4等等的運算,再結合題目的描述,可以猜測vm_ctx[0x10002]相當於sp( 棧指針 ),該虛擬機的所有運算操作都會在它自己維護的棧中進行( 沒有寄存器的概念 )。

大部份handler的實現都比較簡單,配合動調很容易就可以分析出來。

記錄幾個沒那麼容易看出來的handler。

handler7:&v26[-arg]相當於&v26 - arg,這裡是在將棧頂元素與棧頂後arg個元素交換。

handler22:注意_pc += (char)arg,對應匯編是ADD W11, W11, W12,SXTB,其中SXTB是對W12的修飾符,表示將W12的最低8位進行符號擴展,在還原handler時要特別留意這一點。

花億點時間,還原所有handler,實現一個簡單的vm解釋器:

提醒:flag格式為flag{XXXXX-XXXXX-XXXXX-XXXXX},其中X要麼是大寫字母,要麼是數字。

腳本中的測試flag要記得符合這個格式,腳本的輸出日志記為vm.log

前置:在動調的過程中發現handler26會獲取輸入的Flag,加密邏輯大概會在那附近。

vm.log中搜h26_getinput定位到相關位置,首先判斷了input是否flag{ }的格式。

input[5]開始才是真正的內容,對input[5~8]的運算可以總結為:查表、自減、乘0x24。

input[9]有特別的處理,查表、自減操作仍舊保留,不同的是後面會判斷tmp >> 25是否不為0,若是則進行自加、取餘操作。

取餘操作中的模數,會根據輸入的UID不同而變化,即固定UID對應固定的模數。

( 注:以-分隔的每組字串的最個一個元素都是這樣處理的 )

-作為分隔符,每組處理完後會以|來融合。

最後會自減、異或0xc15303fb,這個值是固定的。

綜合上述分析,可以大概用Python還原出加密邏輯:

基於上述加密腳本,似乎無法直接反推出對應的解密邏輯,而且題目描述中提到有多個解也認證了這一點。

密文是0x3EACFC04(0x3EACFC04 ^ 0xc15303fb) == 0xFFFFFFFF,而-1的16進制正是該值,因此只要在最終的自減前,res的值為0,即可滿足等式。

上面提到,以-分隔的每個字串的最個一個元素都會進行取餘的操作( 前提是>>25不為0 ),這一步就可以很方便讓tmp0

-分隔的每組數據計算過程如下,現在的目標是讓tmp等於0,因此d + input_[4]必須是target的整數倍。

此時問題轉化為如何讓d + input_[4] == n * target,其中ntarget都是已知的。

( 注:input_[i]input[i]查表後的結果、target是每組的模數 )

以下腳本用來求input_[0 ~ 4]這幾個未知量( 初始為0 ),原理如下:

注:當input_[j]被確定為0時,是不合理的,要將input_[j - 1] -= 1,然後再重新計算input_[j]的最大值。

運行腳本得到一個可行的Flag為HB0P6-Y84V7-YSWDH-9RZPB

直接hook RegisterNatives,看到flag驗證邏輯在lib52pojie.so!0x134d4

看到一堆~^|操作,但其實它們並非加密邏輯,而是類似ollvm裡的「指令替換」混淆,也叫MBA表達式。

簡單來說就是將一段很簡單的指令( 如a + b ),通過疊加~^|等操作符轉換成完全等價的複雜指令。

由於沒有解混淆的思路,因此只能直接動調慢慢看邏輯。

調用get_input_8取了input的一部份,然後傳入encrypt

encrypt中主要分成3部份,先看encrypt_part1

input.n128_u64[0]是低64位,代表傳入的flag,input.n128_u64[1]是高64位,用來存放結果。

只看與input有關的,hook發現input.n128_u64[0]每輪固定左移-1,即右移1

由此得出input.n128_u64[0]的迭代方式:input = (input >> 1) & (2 ** 64 - 1)

input.n128_u64[1]只與tmp1有關。

frida stalker打印tmp1input_1.n128_u64[1]+=的那個值,發現要將tmp1看成2進制位,每輪都會拼到input_1.n128_u64[1]的低位。

input1 = (input1 << 1) | tmp1,而tmp1其實就是取input.n128_u64[0]的最低位。

最終encrypt_part1可以簡化為:

encrypt_part2的邏輯比encrypt_part1複雜得多,繼續像上面那樣分析實在不太理智( 有心無力 ),本來都打算放棄了,結果當天晚上吾愛放出了提示:

對稱算法,結合分析過程中看到的一些表,嘗試直接搜看看表中的數據。

發現其實是DES算法。

而且根據提示,密鑰是初始化過的。

hook encrypt,打印args[0],發現每個QWORD剛好都是6字節大小的數據,而DES算法的round key也是48位,因此這大概率就是提示所述的初始化過的密鑰。

DES算法:https://blog.csdn.net/nicai_hualuo/article/details/123135670

基於原版DES,遂步分析,還原到最後發現其實是3DES。完整腳本如下:( 腳本是基於上述文章改的 )

輸出flag:

function hook_dlopen(soName) {
    Interceptor.attach(Module.findExportByName(null, "dlopen"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    if (path.indexOf(soName) >= 0) {
                        this.is_can_hook = true;
                    }
                }
            },
            onLeave: function (retval) {
                if (this.is_can_hook) {
                    console.log("hook start...");
                    hook_func(soName)
                }
            }
        }
    );
  
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    if (path.indexOf(soName) >= 0) {
                        this.is_can_hook = true;
                    }
                }
            },
            onLeave: function (retval) {
                if (this.is_can_hook) {
                    console.log("hook start...");
                    hook_func(soName)
                }
            }
        }
    );
}
 
function hook_func(soName) {
    function hook_xorkey(base) {
        Interceptor.attach(base.add(0xE9954), {
            onLeave: function(retval) {
                console.log("[xor_key] ", hexdump(retval))
            }
        })
    }
     
    function hook_test2(base) {
        Interceptor.attach(base.add(0xE98A0), {
            onEnter: function(args) {
                console.log("[call func2] ")
            }
        })
         
        // do_something1
        Interceptor.attach(base.add(0xE74E8), {
            onEnter: function(args) {
                console.log("[call dosomething1] ")
            },
            onLeave: function(retval) {
                console.log("[dosomething1] retval: ", retval)
                retval.replace(0);
                console.log("[dosomething1] retval: ", retval)
            }
        })
         
        Interceptor.attach(Module.findExportByName(null, "getenv"), {
            onEnter: function(args) {
                let a0 = args[0].readCString();
                if (a0.indexOf("name") != -1) {
                    Memory.writeUtf8String(args[0], "name");
                    this.flag = true
                    console.log("[getenv] a0: ", args[0].readCString())
                }
            },
            onLeave: function(retval) {
                if (this.flag) {
                    console.log("retval: ", retval.readCString())
                }
            }
        })
    }
 
    var base = Module.findBaseAddress(soName);
 
    hook_xorkey(base);
    hook_test2(base);
}
 
function main() {
    hook_dlopen("libwuaipojie2025_game.so")
}
 
setImmediate(main)
function hook_dlopen(soName) {
    Interceptor.attach(Module.findExportByName(null, "dlopen"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    if (path.indexOf(soName) >= 0) {
                        this.is_can_hook = true;
                    }
                }
            },
            onLeave: function (retval) {
                if (this.is_can_hook) {
                    console.log("hook start...");
                    hook_func(soName)
                }
            }
        }
    );
  
    Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"),
        {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr !== undefined && pathptr != null) {
                    var path = ptr(pathptr).readCString();
                    if (path.indexOf(soName) >= 0) {
                        this.is_can_hook = true;
                    }
                }
            },
            onLeave: function (retval) {
                if (this.is_can_hook) {
                    console.log("hook start...");
                    hook_func(soName)
                }
            }
        }
    );
}
 
function hook_func(soName) {
    function hook_xorkey(base) {
        Interceptor.attach(base.add(0xE9954), {
            onLeave: function(retval) {
                console.log("[xor_key] ", hexdump(retval))
            }
        })
    }
     
    function hook_test2(base) {
        Interceptor.attach(base.add(0xE98A0), {
            onEnter: function(args) {
                console.log("[call func2] ")
            }
        })
         
        // do_something1
        Interceptor.attach(base.add(0xE74E8), {
            onEnter: function(args) {
                console.log("[call dosomething1] ")
            },
            onLeave: function(retval) {
                console.log("[dosomething1] retval: ", retval)
                retval.replace(0);
                console.log("[dosomething1] retval: ", retval)
            }
        })
         
        Interceptor.attach(Module.findExportByName(null, "getenv"), {
            onEnter: function(args) {
                let a0 = args[0].readCString();
                if (a0.indexOf("name") != -1) {
                    Memory.writeUtf8String(args[0], "name");
                    this.flag = true
                    console.log("[getenv] a0: ", args[0].readCString())
                }
            },
            onLeave: function(retval) {
                if (this.flag) {
                    console.log("retval: ", retval.readCString())
                }
            }
        })
    }
 
    var base = Module.findBaseAddress(soName);
 
    hook_xorkey(base);
    hook_test2(base);
}
 
function main() {
    hook_dlopen("libwuaipojie2025_game.so")
}
 
setImmediate(main)
xor_key1 = [0x2E, 0x4B, 0xEE, 0xC8, 0xE0, 0x95, 0x88, 0x47, 0xB0, 0x72, 0x1B, 0x68, 0x40, 0xD0, 0x0A, 0x84]
# xor_key2 = [0x27, 0xAF, 0xF3, 0xA7, 0xA1, 0x64, 0x51, 0xC3, 0x67, 0x6D, 0x19, 0x04, 0xE9, 0x58, 0xE9, 0x6F]
xor_key2 = [0x77, 0x70, 0x8a]
 
xor_key_list = [xor_key1, xor_key2]
 
data1 = 0x72ECF89BAF8F2748
data2 = 0xB63AE26B0C720798
data3 = 0xF75942
enc = data1.to_bytes(8, 'little') + data2.to_bytes(8, 'little') + data3.to_bytes(3, 'little')
enc = bytearray(enc)
 
xor_keylist_idx = 0
xor_key_idx = 0
flag = ""
for i in range(len(enc)):
    if (i & 0xf) == 0:
        xor_key = xor_key_list[xor_keylist_idx]
        xor_keylist_idx += 1
        xor_key_idx = 0
    flag += chr(xor_key[xor_key_idx] ^ enc[i])
    xor_key_idx += 1
 
print("flag: ", flag)
xor_key1 = [0x2E, 0x4B, 0xEE, 0xC8, 0xE0, 0x95, 0x88, 0x47, 0xB0, 0x72, 0x1B, 0x68, 0x40, 0xD0, 0x0A, 0x84]
# xor_key2 = [0x27, 0xAF, 0xF3, 0xA7, 0xA1, 0x64, 0x51, 0xC3, 0x67, 0x6D, 0x19, 0x04, 0xE9, 0x58, 0xE9, 0x6F]
xor_key2 = [0x77, 0x70, 0x8a]
 
xor_key_list = [xor_key1, xor_key2]
 
data1 = 0x72ECF89BAF8F2748
data2 = 0xB63AE26B0C720798
data3 = 0xF75942
enc = data1.to_bytes(8, 'little') + data2.to_bytes(8, 'little') + data3.to_bytes(3, 'little')
enc = bytearray(enc)
 
xor_keylist_idx = 0
xor_key_idx = 0
flag = ""
for i in range(len(enc)):
    if (i & 0xf) == 0:
        xor_key = xor_key_list[xor_keylist_idx]
        xor_keylist_idx += 1
        xor_key_idx = 0
    flag += chr(xor_key[xor_key_idx] ^ enc[i])
    xor_key_idx += 1
 
print("flag: ", flag)
def write_mem_str(addr, content):
    global vm_ctx
    if type(content) == str:
        for i in range(len(content)):
            vm_ctx[addr + i] = ord(content[i])
    else:
        raise Exception("TODO")
    return addr
 
def write_mem_word(addr, content):
    global vm_ctx
    for i in range(2):
        vm_ctx[addr + i] = content & 0xFF
        content >>= 8
 
def write_mem_arr(addr, arr):
    global vm_ctx
    for i in range(len(arr)):
        vm_ctx[addr + i] = arr[i]
 
def write_mem_dword(addr, content):
    global vm_ctx
    for i in range(4):
        vm_ctx[addr + i] = content & 0xFF
        content >>= 8
 
def read_mem_dword(addr):
    global vm_ctx
    return vm_ctx[addr] | (vm_ctx[addr + 1] << 8) | (vm_ctx[addr + 2] << 16) | (vm_ctx[addr + 3] << 24)
 
def read_mem_word(addr):
    global vm_ctx
    return vm_ctx[addr] | (vm_ctx[addr + 1] << 8)
 
def read_mem_byte(addr):
    global vm_ctx
    return vm_ctx[addr]
 
def push_data(data):
    global vm_ctx
    sp = read_mem_word(0x10002)
    tmp = sp + 4
    write_mem_word(0x10002, tmp)
    write_mem_dword(tmp, data)
 
def pop_data():
    global vm_ctx
    sp = read_mem_word(0x10002)
    data = read_mem_dword(sp)
    write_mem_word(0x10002, sp - 4)
    return data
 
def read_sp_data():
    sp = read_mem_word(0x10002)
    data = read_mem_dword(sp)
    return data
 
def set_sp_data(data):
    sp = read_mem_word(0x10002)
    write_mem_dword(sp, data)
 
def load_opcodes():
    global vm_ctx
    with open("./dump/opcodes", mode = "rb") as f:
        opcodes = bytearray(f.read())
        for i in range(len(opcodes)):
            vm_ctx[0xC000 + i] = opcodes[i]
 
def hex_to_negative(value, bits = 8):
    # 檢查符號位
    if value & (1 << (bits - 1)):
        # 如果是負數,計算其補碼
        value = value - (1 << bits)
    return value
 
def start_vm():
    global vm_ctx, pc, arg, v13
 
    pc = None
    arg = None
    v13 = None
 
    def handler_0_xor():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 ^ n2
        set_sp_data(res)
        print(f"[h0_xor]\t pop, *sp = {hex(n2)} ^ {hex(n1)} = {hex(res)}")
 
    def handler_1_opposite():
        n = read_sp_data()
        set_sp_data(-n)
        print(f"[h1_opposite]\t *sp = -{hex(n)}")
     
    def handler_2_subsp():
        sp = read_mem_word(0x10002)
        write_mem_word(0x10002, sp - 4 * arg)
        print(f"[h2_subsp]\t sp -= {4 * arg}")
     
    def handler_4_orr():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 | n2
        set_sp_data(res)
        print(f"[h4_orr]\t pop, *sp = {hex(n2)} | {hex(n1)} = {hex(res)}")
     
    def handler_5_(): # nglog: maybe some problem
        global pc
        sp = read_mem_word(0x10002)
        v23 = read_sp_data()
        v24 = sp - 8 - 4 * arg + 4
        pc = read_mem_dword(sp - 4)
        write_mem_word(0x10002, v24)
        write_mem_dword(v24, v23)
        print(f"[h5_]\t sp = {hex(v24)}, [{hex(v24)}] = {hex(v23)}, pc = {hex(pc)}")
     
    def handler_6_noeq(): # nglog
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 != n2
        set_sp_data(res)
        print(f"[h6_noeq]\t pop, *sp = {hex(n2)} != {hex(n1)} = {hex(res)}")
     
    def handler_7_swap(): # nglog: some problem
        global arg
        sp = read_mem_word(0x10002)
        n1 = read_mem_dword(sp)     # sp
        n2 = read_mem_dword(sp - 4 * arg) # sp - arg
 
        write_mem_dword(sp, n2)
        write_mem_dword(sp - 4 * arg, n1)
 
        print(f"[h7_swap]\t swap(sp, sp - {arg}) -> swap({hex(n1), hex(n2)})")
     
    def handler_8_and():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 & n2
        set_sp_data(res)
        print(f"[h8_and]\t pop, *sp = {hex(n2)} & {hex(n1)} = {hex(res)}")
     
    def handler_9_lsl():
        sp_data = read_sp_data()
        set_sp_data(sp_data << arg)
        print(f"[h9_lsl]\t *sp = *sp << arg = {hex(sp_data)} << {arg} = {hex(sp_data << arg)}")
 
    def handler_10_not():
        sp_data = read_sp_data()
        set_sp_data(~sp_data)
        print(f"[h10_not]\t *sp = ~(*sp) = ~{hex(sp_data)} = {hex(~sp_data & 0xffffffff)}")
     
    def handler_12_add():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 + n2
        set_sp_data(res)
        print(f"[h12_add]\t pop, *sp = {hex(n2)} + {hex(n1)} = {hex(res)}")
    def handler_14_():
        global pc
        pc += hex_to_negative(arg)
        print(f"[h14_]\t pc += {hex_to_negative(arg)}")
    def handler_15_():
        write_mem_word(0x10004, 257)
        print("[h15_]\t write_mem_word(0x10004, 257)")
     
    def handler_17_lsr():
        sp_data = read_sp_data()
        set_sp_data(sp_data >> arg)
        print(f"[h17_lsr]\t *sp = *sp >> arg = {hex(sp_data)} >> {arg} = {hex(sp_data >> arg)}")
 
    def handler_18_mod():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n2 % n1
        set_sp_data(res)
        print(f"[h18_mod]\t pop, *sp = {hex(n2)} % {hex(n1)} = {hex(res)}")
     
    def handler_20_dword2byte():
        sp = read_mem_word(0x10002)
        sp_data = read_mem_byte(sp)
        set_sp_data(sp_data)
        print(f"[h20_dword2byte]\t *(dword*)sp = *(byte*)sp = {hex(sp_data)}")
 
    def handler_21_mul():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 * n2
        set_sp_data(res)
        print(f"[h21_mul]\t pop, *sp = {hex(n2)} * {hex(n1)} = {hex(res)}")
 
    def handler_22_pushpc(): # nglog
        global pc
        sp = read_mem_word(0x10002)
        pc_ = pc
        pc += hex_to_negative(arg)
        v34 = sp + 4
        write_mem_word(0x10002, v34)
        write_mem_dword(v34, pc_)
        print(f"[h22_pushpc]\t push(pc) -> push({hex(pc_)}), pc += {hex_to_negative(arg)}")
     
    def handler_23_eq(): # nglog
        global pc
        sp = read_mem_word(0x10002)
        v16 = sp - 4
        v15 = sp - 8
        n1 = read_mem_dword(sp)
        n2 = read_mem_dword(sp - 4)
        write_mem_word(0x10002, v15)
        if (v13 == 25) == (n1 == n2):
            print(f"[h23_eq]\t sp = sp - 8")
            return
         
        if arg & 0xFFFFFF00 != 0:
            raise Exception("TODO")
 
        pc += hex_to_negative(arg)
        print(f"[h23_eq]\t sp = sp - 8, pc += {hex_to_negative(arg)} ({hex(arg)})")
 
    def handler_26_getinput():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = read_mem_byte(n1 + n2)
        set_sp_data(res)
        print(f"[h26_getinput]\t pop, *sp = vm_ctx[{hex(n2)} + {hex(n1)}] = {hex(res)}")
     
    def handler_27_pusharg():
        global arg
        sp = read_mem_word(0x10002)
        orig_arg = arg
        arg = read_mem_dword(sp - 4 * arg)
        push_data(arg)
        print(f"[h27_pusharg]\t push({hex(arg)})  arg == [sp - 4 * {orig_arg}]")
     
    def handler_29_pusharg2(): # nglog
        push_data(arg)
        print(f"[h29_pusharg2]\t push({hex(arg)})")
 
    def handler_30_sub1():
        sp_data = read_sp_data()
        set_sp_data(sp_data - 1)
        print(f"[h30_sub1]\t *sp = *sp - 1 = {hex(sp_data)} - 1 = {hex(sp_data - 1)}")
     
    pc = read_mem_word(0x10000)
     
    while True:
        pc_1 = pc + 1
        cur_opcode = read_mem_byte(pc)
        arg = cur_opcode & 7
        if arg != 7:
            pc += 1
            v13 = cur_opcode >> 3
            _opcode = v13 - 1
        else:
            pc += 2
            arg = read_mem_byte(pc_1)
            v13 = cur_opcode >> 3
            _opcode = v13 - 1
            if v13 - 1 > 0x1E:
                raise Exception("TODO")
                break
        if _opcode == 0:
            handler_0_xor()
        elif _opcode == 1:
            handler_1_opposite()
        elif _opcode == 2:
            handler_2_subsp()
        elif _opcode == 3 or _opcode == 25:
            continue
        elif _opcode == 4:
            handler_4_orr()
        elif _opcode == 5:
            handler_5_()
        elif _opcode == 6:
            handler_6_noeq()
        elif _opcode == 7:
            handler_7_swap()
        elif _opcode == 8:
            handler_8_and()
        elif _opcode == 9:
            handler_9_lsl()
        elif _opcode == 10:
            handler_10_not()
        elif _opcode == 12:
            handler_12_add()
        elif _opcode == 14:
            handler_14_()
        elif _opcode == 15:
            handler_15_()
            break
        elif _opcode == 17:
            handler_17_lsr()
        elif _opcode == 18:
            handler_18_mod()
        elif _opcode == 20:
            handler_20_dword2byte()
        elif _opcode == 21:
            handler_21_mul()
        elif _opcode == 22:
            handler_22_pushpc()
        elif _opcode == 23 or _opcode == 24:
            handler_23_eq()
        elif _opcode == 26:
            handler_26_getinput()
        elif _opcode == 27:
            handler_27_pusharg()
        elif _opcode == 29:
            handler_29_pusharg2()
        elif _opcode == 30:
            handler_30_sub1()
        else:
            print("else _opcode: ", _opcode)
            raise Exception("TODO")
            break
     
    write_mem_word(0x10000, pc)
    res = read_sp_data()
    return res
 
# init vm_ctx
vm_ctx = [0] * 0x10006
 
load_opcodes()
 
write_mem_dword(0x10000, 0x8000C000)
write_mem_word(0x10004, 0)
 
write_mem_arr(0x204 * 0x10, [0x00, 0x03, 0x0F, 0x20, 0x0D, 0x02, 0x23, 0x06, 0x1B, 0x14,0x0E, 0x01, 0x16, 0x19, 0x08, 0x12])
write_mem_arr(0x205 * 0x10, [0x1F, 0x17, 0x24, 0x0B, 0x1E, 0x07, 0x1A, 0x05, 0x18, 0x1D, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00])
write_mem_arr(0x203 * 0x10, [0x09, 0x0A, 0x10, 0x15, 0x21, 0x13, 0x0C, 0x04, 0x11, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
 
write_mem_str(0x1000, "flag{44444-44444-44444-44444}") # input flag
 
push_data(1898208) # uid
push_data(0x1000)
push_data(0x2000)
 
res = start_vm()
print("[res]: ", hex(res))
def write_mem_str(addr, content):
    global vm_ctx
    if type(content) == str:
        for i in range(len(content)):
            vm_ctx[addr + i] = ord(content[i])
    else:
        raise Exception("TODO")
    return addr
 
def write_mem_word(addr, content):
    global vm_ctx
    for i in range(2):
        vm_ctx[addr + i] = content & 0xFF
        content >>= 8
 
def write_mem_arr(addr, arr):
    global vm_ctx
    for i in range(len(arr)):
        vm_ctx[addr + i] = arr[i]
 
def write_mem_dword(addr, content):
    global vm_ctx
    for i in range(4):
        vm_ctx[addr + i] = content & 0xFF
        content >>= 8
 
def read_mem_dword(addr):
    global vm_ctx
    return vm_ctx[addr] | (vm_ctx[addr + 1] << 8) | (vm_ctx[addr + 2] << 16) | (vm_ctx[addr + 3] << 24)
 
def read_mem_word(addr):
    global vm_ctx
    return vm_ctx[addr] | (vm_ctx[addr + 1] << 8)
 
def read_mem_byte(addr):
    global vm_ctx
    return vm_ctx[addr]
 
def push_data(data):
    global vm_ctx
    sp = read_mem_word(0x10002)
    tmp = sp + 4
    write_mem_word(0x10002, tmp)
    write_mem_dword(tmp, data)
 
def pop_data():
    global vm_ctx
    sp = read_mem_word(0x10002)
    data = read_mem_dword(sp)
    write_mem_word(0x10002, sp - 4)
    return data
 
def read_sp_data():
    sp = read_mem_word(0x10002)
    data = read_mem_dword(sp)
    return data
 
def set_sp_data(data):
    sp = read_mem_word(0x10002)
    write_mem_dword(sp, data)
 
def load_opcodes():
    global vm_ctx
    with open("./dump/opcodes", mode = "rb") as f:
        opcodes = bytearray(f.read())
        for i in range(len(opcodes)):
            vm_ctx[0xC000 + i] = opcodes[i]
 
def hex_to_negative(value, bits = 8):
    # 檢查符號位
    if value & (1 << (bits - 1)):
        # 如果是負數,計算其補碼
        value = value - (1 << bits)
    return value
 
def start_vm():
    global vm_ctx, pc, arg, v13
 
    pc = None
    arg = None
    v13 = None
 
    def handler_0_xor():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 ^ n2
        set_sp_data(res)
        print(f"[h0_xor]\t pop, *sp = {hex(n2)} ^ {hex(n1)} = {hex(res)}")
 
    def handler_1_opposite():
        n = read_sp_data()
        set_sp_data(-n)
        print(f"[h1_opposite]\t *sp = -{hex(n)}")
     
    def handler_2_subsp():
        sp = read_mem_word(0x10002)
        write_mem_word(0x10002, sp - 4 * arg)
        print(f"[h2_subsp]\t sp -= {4 * arg}")
     
    def handler_4_orr():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 | n2
        set_sp_data(res)
        print(f"[h4_orr]\t pop, *sp = {hex(n2)} | {hex(n1)} = {hex(res)}")
     
    def handler_5_(): # nglog: maybe some problem
        global pc
        sp = read_mem_word(0x10002)
        v23 = read_sp_data()
        v24 = sp - 8 - 4 * arg + 4
        pc = read_mem_dword(sp - 4)
        write_mem_word(0x10002, v24)
        write_mem_dword(v24, v23)
        print(f"[h5_]\t sp = {hex(v24)}, [{hex(v24)}] = {hex(v23)}, pc = {hex(pc)}")
     
    def handler_6_noeq(): # nglog
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 != n2
        set_sp_data(res)
        print(f"[h6_noeq]\t pop, *sp = {hex(n2)} != {hex(n1)} = {hex(res)}")
     
    def handler_7_swap(): # nglog: some problem
        global arg
        sp = read_mem_word(0x10002)
        n1 = read_mem_dword(sp)     # sp
        n2 = read_mem_dword(sp - 4 * arg) # sp - arg
 
        write_mem_dword(sp, n2)
        write_mem_dword(sp - 4 * arg, n1)
 
        print(f"[h7_swap]\t swap(sp, sp - {arg}) -> swap({hex(n1), hex(n2)})")
     
    def handler_8_and():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 & n2
        set_sp_data(res)
        print(f"[h8_and]\t pop, *sp = {hex(n2)} & {hex(n1)} = {hex(res)}")
     
    def handler_9_lsl():
        sp_data = read_sp_data()
        set_sp_data(sp_data << arg)
        print(f"[h9_lsl]\t *sp = *sp << arg = {hex(sp_data)} << {arg} = {hex(sp_data << arg)}")
 
    def handler_10_not():
        sp_data = read_sp_data()
        set_sp_data(~sp_data)
        print(f"[h10_not]\t *sp = ~(*sp) = ~{hex(sp_data)} = {hex(~sp_data & 0xffffffff)}")
     
    def handler_12_add():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 + n2
        set_sp_data(res)
        print(f"[h12_add]\t pop, *sp = {hex(n2)} + {hex(n1)} = {hex(res)}")
    def handler_14_():
        global pc
        pc += hex_to_negative(arg)
        print(f"[h14_]\t pc += {hex_to_negative(arg)}")
    def handler_15_():
        write_mem_word(0x10004, 257)
        print("[h15_]\t write_mem_word(0x10004, 257)")
     
    def handler_17_lsr():
        sp_data = read_sp_data()
        set_sp_data(sp_data >> arg)
        print(f"[h17_lsr]\t *sp = *sp >> arg = {hex(sp_data)} >> {arg} = {hex(sp_data >> arg)}")
 
    def handler_18_mod():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n2 % n1
        set_sp_data(res)
        print(f"[h18_mod]\t pop, *sp = {hex(n2)} % {hex(n1)} = {hex(res)}")
     
    def handler_20_dword2byte():
        sp = read_mem_word(0x10002)
        sp_data = read_mem_byte(sp)
        set_sp_data(sp_data)
        print(f"[h20_dword2byte]\t *(dword*)sp = *(byte*)sp = {hex(sp_data)}")
 
    def handler_21_mul():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = n1 * n2
        set_sp_data(res)
        print(f"[h21_mul]\t pop, *sp = {hex(n2)} * {hex(n1)} = {hex(res)}")
 
    def handler_22_pushpc(): # nglog
        global pc
        sp = read_mem_word(0x10002)
        pc_ = pc
        pc += hex_to_negative(arg)
        v34 = sp + 4
        write_mem_word(0x10002, v34)
        write_mem_dword(v34, pc_)
        print(f"[h22_pushpc]\t push(pc) -> push({hex(pc_)}), pc += {hex_to_negative(arg)}")
     
    def handler_23_eq(): # nglog
        global pc
        sp = read_mem_word(0x10002)
        v16 = sp - 4
        v15 = sp - 8
        n1 = read_mem_dword(sp)
        n2 = read_mem_dword(sp - 4)
        write_mem_word(0x10002, v15)
        if (v13 == 25) == (n1 == n2):
            print(f"[h23_eq]\t sp = sp - 8")
            return
         
        if arg & 0xFFFFFF00 != 0:
            raise Exception("TODO")
 
        pc += hex_to_negative(arg)
        print(f"[h23_eq]\t sp = sp - 8, pc += {hex_to_negative(arg)} ({hex(arg)})")
 
    def handler_26_getinput():
        n1 = pop_data()     # *sp
        n2 = read_sp_data() # *(sp - 1)
        res = read_mem_byte(n1 + n2)
        set_sp_data(res)
        print(f"[h26_getinput]\t pop, *sp = vm_ctx[{hex(n2)} + {hex(n1)}] = {hex(res)}")
     
    def handler_27_pusharg():
        global arg
        sp = read_mem_word(0x10002)
        orig_arg = arg
        arg = read_mem_dword(sp - 4 * arg)
        push_data(arg)
        print(f"[h27_pusharg]\t push({hex(arg)})  arg == [sp - 4 * {orig_arg}]")
     
    def handler_29_pusharg2(): # nglog
        push_data(arg)
        print(f"[h29_pusharg2]\t push({hex(arg)})")
 
    def handler_30_sub1():
        sp_data = read_sp_data()
        set_sp_data(sp_data - 1)
        print(f"[h30_sub1]\t *sp = *sp - 1 = {hex(sp_data)} - 1 = {hex(sp_data - 1)}")
     
    pc = read_mem_word(0x10000)
     
    while True:
        pc_1 = pc + 1
        cur_opcode = read_mem_byte(pc)
        arg = cur_opcode & 7
        if arg != 7:
            pc += 1
            v13 = cur_opcode >> 3
            _opcode = v13 - 1
        else:
            pc += 2
            arg = read_mem_byte(pc_1)
            v13 = cur_opcode >> 3
            _opcode = v13 - 1
            if v13 - 1 > 0x1E:
                raise Exception("TODO")
                break
        if _opcode == 0:
            handler_0_xor()
        elif _opcode == 1:
            handler_1_opposite()
        elif _opcode == 2:
            handler_2_subsp()
        elif _opcode == 3 or _opcode == 25:
            continue
        elif _opcode == 4:
            handler_4_orr()
        elif _opcode == 5:
            handler_5_()
        elif _opcode == 6:
            handler_6_noeq()
        elif _opcode == 7:
            handler_7_swap()
        elif _opcode == 8:
            handler_8_and()
        elif _opcode == 9:
            handler_9_lsl()
        elif _opcode == 10:
            handler_10_not()
        elif _opcode == 12:
            handler_12_add()
        elif _opcode == 14:
            handler_14_()
        elif _opcode == 15:
            handler_15_()
            break
        elif _opcode == 17:
            handler_17_lsr()
        elif _opcode == 18:
            handler_18_mod()
        elif _opcode == 20:
            handler_20_dword2byte()
        elif _opcode == 21:
            handler_21_mul()
        elif _opcode == 22:
            handler_22_pushpc()
        elif _opcode == 23 or _opcode == 24:
            handler_23_eq()
        elif _opcode == 26:
            handler_26_getinput()
        elif _opcode == 27:
            handler_27_pusharg()
        elif _opcode == 29:
            handler_29_pusharg2()
        elif _opcode == 30:

[招生]科锐逆向工程师培训(2025年3月11日实地,远程教学同时开班, 第52期)!

收藏
免费 10
支持
分享
赞赏记录
参与人
雪币
留言
时间
云水泱泱
为你点赞!
2025-3-3 11:13
iamshy
+1
感谢你的积极参与,期待更多精彩内容!
2025-2-19 10:48
gal2xy
你的帖子非常有用,感谢分享!
2025-2-19 10:10
KXXTEST
感谢你的贡献,论坛因你而更加精彩!
2025-2-18 11:07
CIH_D39
+1
感谢你的积极参与,期待更多精彩内容!
2025-2-17 18:14
jiyuren
谢谢你的细致分析,受益匪浅!
2025-2-14 14:11
cxbcxb
这个讨论对我很有帮助,谢谢!
2025-2-13 20:48
TubituX
你的帖子非常有用,感谢分享!
2025-2-13 15:18
Shangwendada
+3
期待更多优质内容的分享,论坛有你更精彩!
2025-2-13 11:33
.KK
期待更多优质内容的分享,论坛有你更精彩!
2025-2-13 10:13
最新回复 (4)
雪    币: 484
活跃值: (650)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
强!
2025-2-13 10:18
0
雪    币: 3853
活跃值: (3428)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
很强,但是不懂!
2025-2-15 09:34
0
雪    币: 2660
活跃值: (2220)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
4
jiaoxiake 很强,但是不懂!
2025-2-15 11:30
0
雪    币: 48
活跃值: (2298)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
大佬太强了
2025-2-17 21:50
0
游客
登录 | 注册 方可回帖
返回

账号登录
验证码登录

忘记密码?
没有账号?立即免费注册