簡單寫一下Android部份的解題思路。
明顯的xxtea特徵。


解密後直接得到flag


目標是找到秘鑰。

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

是個native函數。

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

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

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

anti2
、do_something1
也同理,皆因為decrypt_str
的問題導致後續的邏輯失效。
繼續向下跟,看到它動態計算出一個函數地址,大概率就是加密函數,最後與密文進行對比。
一開始以為動態計算的那個函數地址是固定的,後來才發現有兩個不同的地址,會隨著上面anti1
、anti2
、do_something1
、getenv
等函數返回的結果而改變。
類似蜜罐的概念,當觸發anti邏輯後,不主動殺死APP,而是改變程序的執行流,導向錯誤的分支。

func1
、func2
如下,前者是錯誤的分支,後者是正確的,我的環境默認會走func1
。
可以看到兩者的加密方式都是相同的異或加密,不同的只有異或的值。


經測試發現,手動hook getenv
、do_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
正式啟動虛擬機進行計算。
一開始會通過一些運算獲取_opcode
和arg
,前者是操作碼、後者是一些固定的參數( 在不同的操作碼中都有不同的含義 )。

接著就是vm最經典的一大段switch,每個case對應不同的handler,實現了不同的功能。
每個handler裡基本上都會用到vm_ctx[0x10002]
,一些參數、中間值、計算結果都會存放在vm_ctx[0x10002]
指向的位置。
而且可以看到vm_ctx[0x10002] + 4
、vm_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
),這一步就可以很方便讓tmp
歸0
。
以-
分隔的每組數據計算過程如下,現在的目標是讓tmp
等於0
,因此d + input_[4]
必須是target
的整數倍。
此時問題轉化為如何讓d + input_[4] == n * target
,其中n
、target
都是已知的。
( 注: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打印tmp1
、input_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
=
[
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
=
[
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()
n2
=
read_sp_data()
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()
n2
=
read_sp_data()
res
=
n1 | n2
set_sp_data(res)
print
(f
"[h4_orr]\t pop, *sp = {hex(n2)} | {hex(n1)} = {hex(res)}"
)
def
handler_5_():
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():
n1
=
pop_data()
n2
=
read_sp_data()
res
=
n1 !
=
n2
set_sp_data(res)
print
(f
"[h6_noeq]\t pop, *sp = {hex(n2)} != {hex(n1)} = {hex(res)}"
)
def
handler_7_swap():
global
arg
sp
=
read_mem_word(
0x10002
)
n1
=
read_mem_dword(sp)
n2
=
read_mem_dword(sp
-
4
*
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()
n2
=
read_sp_data()
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()
n2
=
read_sp_data()
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()
n2
=
read_sp_data()
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()
n2
=
read_sp_data()
res
=
n1
*
n2
set_sp_data(res)
print
(f
"[h21_mul]\t pop, *sp = {hex(n2)} * {hex(n1)} = {hex(res)}"
)
def
handler_22_pushpc():
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():
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()
n2
=
read_sp_data()
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():
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
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}"
)
push_data(
1898208
)
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()
n2
=
read_sp_data()
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()
n2
=
read_sp_data()
res
=
n1 | n2
set_sp_data(res)
print
(f
"[h4_orr]\t pop, *sp = {hex(n2)} | {hex(n1)} = {hex(res)}"
)
def
handler_5_():
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():
n1
=
pop_data()
n2
=
read_sp_data()
res
=
n1 !
=
n2
set_sp_data(res)
print
(f
"[h6_noeq]\t pop, *sp = {hex(n2)} != {hex(n1)} = {hex(res)}"
)
def
handler_7_swap():
global
arg
sp
=
read_mem_word(
0x10002
)
n1
=
read_mem_dword(sp)
n2
=
read_mem_dword(sp
-
4
*
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()
n2
=
read_sp_data()
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()
n2
=
read_sp_data()
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()
n2
=
read_sp_data()
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()
n2
=
read_sp_data()
res
=
n1
*
n2
set_sp_data(res)
print
(f
"[h21_mul]\t pop, *sp = {hex(n2)} * {hex(n1)} = {hex(res)}"
)
def
handler_22_pushpc():
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():
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()
n2
=
read_sp_data()
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():
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期)!