在windows流行的时候,虚拟机保护是多人不敢碰的东西现在依然也是如此,pc的性能比移动端性能要高出不少,虚拟化和变异的代码多到令人发指,因此在加密保护强度上要比移动端要强很多很多,为了移动端App更好的体验(ANR率)移动端加密强度短时间内不会达到pc上的强度,随着移动cpu性能越来越好相信加密强度会逐年加强。
早年兴趣使然分析研究过windows端VMProtect、Safengine Shielden、Themida、VProtect、Enigma Protector等等虚拟机,最近发现国内流行的短视频也有虚拟机加密同时也比较感兴趣,便开始了我的分析之旅。
分析任何虚拟机必须要扣汇编指令级细节。
安卓诞生这么多年了至今没有像windows端olldbg、x64dbg那样友好的调试器,IDA PRO虽然自带了安卓调试器总是没有相像中的稳定。lldb作为移动端iOS和android开发的御用调试器,带源码调试在开发环境中还算比较友好,而汇编级调试只能输入命令行了,这是很多用惯了gui调试器的人接受不了的,但是个人发现lldb调试稳定性出奇的好,功能上比IDA Pro的安卓调试器强大太多了。
libEncryptor.so一共包含了三套虚拟机,三套虚拟机各自独立并且代码一模一样,本文重点只分析vm2虚拟机 。 虚拟机指令编解码 参考借鉴了arm64的一部分规则,并实现了自己的一套规则,在后面的解码分析中会有很多和arm64解码相似的地方。 另外虚拟机并没有像VMProtect那样将一条指令分割成多条"微指令"的方式,此虚拟机没有把当前真实的上下文放到虚拟机上下文去模拟执行,而是运行了一套自己单独的上下文。
在函数中调用虚拟机时会传入一个指针数组类型参数变量,这是传入到虚拟机入口的唯一参数。
c伪代码来表示函数调用虚拟机入口
反汇编版本:
IDA Pro查看入口的cfg图,复杂程序看似很难其实一点都不简单,话说回来cfg看起来和ollvm的混淆平坦化非常相似,其实和ollvm混淆关系不大,只不过一部分的switch被拉平了,在了解调度逻辑后分析也不算复杂。 在代码中依然能看到两个ollvm swtich var变量,其作用没有详细分析,但整个cfg图确定与ollvm关系不是很大,猜测开启ollvm后性能会大幅下降影响app启动速度了。 在进入虚拟机运行时前,在入口需要准备虚拟机所需的内存和参数。对虚拟机内存布局情况必须了解如指掌,这样在动态和静态分析时才不会迷失方向。
vm2_run仅仅只分配了保存被调用者寄存器的堆栈内存空间,并没有分配空闲的堆栈内存,在虚拟机真实开始之前会将传递进来的5个参数即0x-x4对虚拟机中的虚拟寄存器和真实专用寄存器进行初始化。 vm_run还初始化了解码opcode的switch表,在初始化时发现一共初始化了6张switch表,当然在handler中还存在其他switch表,这么多表是如何来的?猜测编写时只有1-2张表,在编译器优化后表就被分割成多块了。
虚拟寄存器初始化 vm2_run初始化时会将传递的5个参数赋值给虚拟寄存器,其中包括PC和SP的值。
真实专用寄存器 虚拟机运行时使用了真实虚拟器,其中包括临时寄存器和专用寄存器,临时寄存器保存多种类型的值,而专用寄存器在虚拟机从开始到退出只保存一种指定类型数据或恒定不变。 opcode位域伪代码: w12保存了4位32字节的opcode,在opcode首次解码 时,位域中的变量会放到真实寄存器。 位域伪代码示例:w12[26]
: 取第26位到放到入目标的26位w12[26->0]
: 取第26位并放入到目标的指定位 w12[27-26->1-0]
: 取27位和26位放入到目标第1位和第0位|
: 按位或
虚拟机context 虚拟机中也有专用寄存器,在调用外部函数时,其中x4
虚拟机中保存外部函数地址,x5
虚拟机中保存参数指针,x25
虚拟机中调用外部函数时的跳板地址。另外虚拟寄存器和aarch64中的寄存器并不是一一对应的,在这里只是对每个虚拟寄存器启了一个相应的名字方便理解和记忆 。
pOpcode取出4个字节的opcode并取得低5位解码出op1。
在opcode首次解码 时会解码4个寄存器操作数,从中提取4个位域的字段,分别保存到真实专用寄存器 w8、w9、w10、w11,在arm64指令集中当指令是MADD、MSUB、UMADDL、UMSUBL、SMADDL、SMADDL等会有4个寄存器操作数的情况,在这里同样也是如此。 首次解码时位域布局:w12[31,30-26,25-21,20-16,15-12,11-6,5-0] w12[5-0:6] = op1 w12[11-6:6] = op2 w12[15-12:4]|[31:1] = Xm/Wm w12[20-16:5] = Xt/Wt w12[25-21:5] = Xn/Wn w12[30-26:5] =Xa/Waw8
: Rd(Xt/Wt)目标寄存器操作数,w12[20-16->5-0],取出16-20位保存最低位,5位可以表示0-31个寄存器。w9
: Rn(Xn/Wn)(第一个源寄存器操作数,w12[25-21->5-0],取出21-25位保存最低位,5位可以表示0-31个寄存器。w10
: Rm(Xm/Wm)第二个源寄存器操作数,w12[15->4] | w12[14->3] | w12[13->2] | w12[12->1] | w12[31->0],5位可以表示0-31个寄存器。w11
: Ra(Xa/Wa)第三个源寄存器操作数,w12[30->4] | w12[29->3] | w12[28->2] | w12[27-26->1-0],5位可以表示0-31个寄存器。 寄存器操作数伪代码表示如下:操作数大小
: X为64位操作数、W为32位操作数。目标操作数
: d=destination register, t=target register。源寄存器
:第一个源寄存器为n,第二个寄存器为m,第三个寄存器为a。R
: 表示寄存器64或32位操作数,X是64位操作数、W代表32位操作数。
在高级语言中如果一个switch太多,在某些编译器编译优化后出现在多张switch子表和子表的子表的情况,对于一些相同代码的多个case会合并到一个case中再次switch分发的情况。 根据编译器的优化编译的特性,在处理switch的case为了减少查找次数找到最终的case,在代码中会经常看到大于(GT)、小于(LE)等分支跳转,看到这个不要迷惑,这是编译器优化case的结果,这样做的目的是减少查找次数使用了类似二分查找的算法,当看到B.EQ的跳转目标和B.NE的下一条指令就是匹配到了case常量了。 在首次解码 后分发过程中通常还会有二次解码 ,除了MADD和MSUB等等指令有4个寄存器操作数,指令只需一般指令只有2-3个寄存器操作数,一条完整的arm64指令至少需要二个寄存器操作数,这里也同样如此,当指令只有二个寄存器操作数时即一个目标操作数Xt和第一个源操作数Xn,其他的位域字段就会空闲下来,例如:op2、Xm、Xa,在二次解码时这些空闲的位域字段原有的值就会覆盖被再次利用组成其他寻址方式例如:shift、extend、imm等等。 在虚拟机指令op1的值是11(0xb)时,分发处理会解码op2,解码op2时Xt、Xn、Xm等操作数位置会发生变化,原有的x10/w10第三个源操作数在op2中变成目标操作数,第一个源操作数变成x8/w8,第二个源操作数变成x9/w9,各操作数的位域解码方式不变,变的只是操作数角色。Xt
:Rd(Xt/Wt)目标寄存器操作数(x10/w10),w12[15->4] | w12[14->3] | w12[13->2] | w12[12->1] | w12[31->0],5位可以表示0-31个寄存器。Xn
: Rn(Xn/Wn)(第一个源寄存器操作数(x8/w8),w12[20-16->5-0],取出16-20位保存最低位,5位可以表示0-31个寄存器。Xm
: Rm(Xm/Wm)第二个源寄存器操作数(x9/w9),w12[25-21->5-0],取出21-25位保存最低位,5位可以表示0-31个寄存器。
从op1的取值范围为0-63一共64条指令,当op1是11时还有存在op2和op3的情况,由于虚拟机的handler太过庞大分析所有的指令太过耗时,我们目的是还原代码逻辑,只需分析执行过的handler,对于没有执行过的handler放弃分析。 在了解了op1解码方式后,通过脚本得到执行次数最多的指令并优先分析:
得到执行次数最多的指令:
从python打印的结果来看23、11、40前面三个指令使用最为频繁,因篇幅关系只分析这三条指令,其中op1值是11的还存在第二个操作码op2,这里选择op1=11 & op2=12的指令进行分析。
准备下一条指令: pc指针地址加4
当op1值等于11时会解码第二个或第三个操作码。
分析完取指、解码、执行后大体得到了一个模糊的虚拟机执行框架,为了方便记忆和理解使用c伪代码来描述。
使用脚本解析opcode的op1和op2打印所有需要分析的handler。
一共打印出15个handler,好在需要分析还原的指令不多:
在15个handler并还原后,现在重新编写脚本decode_opcode.py
解码opcode,将打印还原的指令打印出伪汇编代码并保存文件ttencryptor.asm
和generate_aes_key_iv.asm
。
vm2还原的伪汇编代码,经过分析主要做了这些事件:
由于vm2会调用vm3生成aes的key和iv,因此vm3的代码也需要解析还原generate_aes_key_iv.asm :
这就是libEncryptor.so中ttEncrypt函数的加密算法了。
为了验证算法是否有效,这里使用了dy模块中的ttEncrypt算法和tt的设备注册代码:
结果:
在分析完之后虚拟机保护的强度没有想像中的那么好,在分析过的虚拟化加密强度非要分10个等级的话,VMProtect为10级、Safengine Shielden强度为9级、Themida强度9级、VProtect强度7级、Enigma Protector强度3级,而它的强度等级仅为1级。
void
vm_entry(*
int
args)
void
ttEncrypt(
char
* buff,
int
buff_size) {
int
dst_size = size +0x76;
char
* pDstBuff =
malloc
(size +0x76);
vm_entry(buff, size, pDstBuff, &dst_size);
}
void
ttEncrypt(
char
* buff,
int
buff_size) {
int
dst_size = size +0x76;
char
* pDstBuff =
malloc
(size +0x76);
vm_entry(buff, size, pDstBuff, &dst_size);
}
SP
类型
变量名
注释
0x0
未使用
0x8
char *
pSrcBuffer
0x10
int
srcSize
0x18
char *
pDstBuffer
0x20
int *
pDstBufferSize
0x28
void *
pCall_register_trampoline
0x30
void *
pVMMemoryEnd
偏移0x510
0x38
vmMemoryStart
虚拟机运行时专用内存起始位置
...
0x510
vmMemoryEnd
虚拟机运行时内存结束位置
0x518
0x520
x28
0x528
x19
0x530
x29
上一个栈桢地址
0x538
x30
vm2_run(
void
* pOpcode,
void
* pArgs,
void
* pReserve,
void
* pExternalFunc,
void
* pVmData);
vm2_run(
void
* pOpcode,
void
* pArgs,
void
* pReserve,
void
* pExternalFunc,
void
* pVmData);
虚拟寄存器
参数
注释
x0
x0始终为0,XZR寄存器?
x4
arg2: pArgs
x5
arg3: pReserve
x6
arg4: pExternalFunc
x7
arg4: pVmData->pCallRegisterTrampolineFunction
x29(SP)
arg5: pVmData->pVmMemoryLimit - 0x150
SP的初始值
x31(LR)
初始值为0,寄存器名不确定,vm退出时保存退出代码编号
PC
arg1: pOpcode
真实寄存器
注释
x0
temp/pcode
x1
temp,保存[x19-0x20]的值某种流程控制
x2
temp
x3
temp
x4
虚拟寄存x4,初始化时保存pBufferInfo(x1),虚拟机中保存跳板函数地址
x5
虚拟寄存x5,初始化时保存数值为0,虚拟机运行时跳板函数的参数指针
x6
ollvm混淆switch_var,初始值:0x400000b,这个应该是llvm混淆的switch var
w7
ollvm混淆switch_var,初始值:0x200fff,这个应该是llvm混淆的switch var
w8
w12[20-16] operand1 Xt/Xm,det register index?
w9
w12[25-21] operand2 Xn,src register index?
w10
w12[15->4] | w12[14->3] | w12[13->2] | w12[12->1] | w12[31->0],5个位合并到低5位
w11
w12[30->4] | w12[29->3] | w12[28->2] | w12[27-26->0-1],组成的低5位
w12
32位的opcode
w13
w12[31]
w14
w12[30]
w15
w12[29]
w16
w12[28]
w17
w12[27]
w18
w12[26]
x19
虚拟机下文负偏移指针 指向可使用内存最高上限的地址与vmMemoryLimit值相同,使用负偏移 对上下文进行访问。
x20
call_register_trampoline 跳板地址
x21
Context,上下文指针
x22
switch_table7
x23
switch_table6
w24
默认为1
x25
switch_table5
x26
switch_table3
x27
switch_table_main
x28
switch_table2
x29(fp)
未使用
x30(lr)
switch_table_4(3A)
负偏移
虚拟寄存器
注释
-0x150
虚拟机堆栈SP初始位置
-0x148
-0x140
-0x138
pc
pc指针,真实寄存器x21中的值指向此地址,handler使用
-0x130
x0
初始化值:0,虚拟机中开始到结束始终为0,XZR寄存器?
-0x128
x1
-0x120
x2
-0x118
x3
-0x110
x4
初始化值:pBufferInfo,专用寄存器:虚拟机中调用外部函数时保存外部函数地址
-0x108
x5
初始化值: 0,专用寄存器:虚拟机中调用外部函数时保存参数指针
-0x100
x6
初始化值: vm2_external_func_list
-0xF8
x7
初始化值: call_register_trampoline_function
-0xF0
x8
-0xE8
x9
-0xE0
x10
-0xD8
x11
-0xD0
x12
-0xC8
x13
-0xC0
x14
-0xB8
x15
-0xB0
x16
-0xA8
x17
-0xA0
x18
-0x98
x19
-0x90
x20
-0x88
x21
-0x80
x22
-0x78
x23
-0x70
x24
-0x68
x25
虚拟机中的专用寄存器:虚拟机中调用外部函数时的跳板地址
-0x60
x26
-0x58
x27
-0x50
x28
-0x48
x29(SP)
虚拟机堆栈SP, 初始化时指向-0x150
-0x40
x30
-0x38
x31(LR)
当值为0时退出虚拟机
-0x30
-0x28
-0x20
0
流程控制状态标记,值范围0-3,0:正常执行状态,2和3:程序中包含分支跳转某种流程,3和1:call某个地址函数
-0x18
new pc/call某个地址函数的地址/为0时退出虚拟机
-0x10
LR,在调用调用函数结束后返回虚拟机地址
-0x8
起始pc指针,一部分分支跳转指令参考的起始基址,例如: 跳转目标地址=pc起始地址+offset
# 初始化
LDP X20, X19, [X4] ;x20:call_register_trampoline,0x19:pVmMemoryLimit
SUB X21, X19, #0x138 ;x19-0x138=x21计算出pc指针在负偏移指针的内存位置
STR X0, [X21] ;保存pc到x21,此时x0和x21中的值相同并被关联。
# 取opcode
LDR W12, [X0] ;取出4字节opcode
AND W10, W12, #0x3F ;opcode的低5位为op1
CMP W10, #0x3F ;op1的值最大只能小于63,说明op1只有0-63一共64个
B.HI next_pc ;下一条指令
# 初始化
LDP X20, X19, [X4] ;x20:call_register_trampoline,0x19:pVmMemoryLimit
SUB X21, X19, #0x138 ;x19-0x138=x21计算出pc指针在负偏移指针的内存位置
STR X0, [X21] ;保存pc到x21,此时x0和x21中的值相同并被关联。
# 取opcode
LDR W12, [X0] ;取出4字节opcode
AND W10, W12, #0x3F ;opcode的低5位为op1
CMP W10, #0x3F ;op1的值最大只能小于63,说明op1只有0-63一共64个
B.HI next_pc ;下一条指令
import
struct
pcode_start
=
0xB090
pcode_size
=
0x2D8
with
open
(
"libEncryptor.so"
,
"rb"
) as f:
content
=
f.read()
bytes_code
=
content[pcode_start : pcode_start
+
pcode_size]
insts_sets
=
{}
for
pc
in
range
(
0
, pcode_size,
4
):
word
=
struct.unpack(
"<I"
, bytes_code[pc : pc
+
4
])
if
len
(word) >
0
:
opcode
=
word[
0
]
op1
=
opcode &
0x3F
if
insts_sets.get(op1,
None
)
=
=
None
:
insts_sets[op1]
=
1
else
:
insts_sets[op1]
+
=
1
sorted_dict
=
dict
(
sorted
(insts_sets.items(), key
=
lambda
item: item[
1
], reverse
=
True
))
for
inst, count
in
sorted_dict.items():
print
(f
'op1: {inst}, count: {count}'
)
import
struct
pcode_start
=
0xB090
pcode_size
=
0x2D8
with
open
(
"libEncryptor.so"
,
"rb"
) as f:
content
=
f.read()
bytes_code
=
content[pcode_start : pcode_start
+
pcode_size]
insts_sets
=
{}
for
pc
in
range
(
0
, pcode_size,
4
):
word
=
struct.unpack(
"<I"
, bytes_code[pc : pc
+
4
])
if
len
(word) >
0
:
opcode
=
word[
0
]
op1
=
opcode &
0x3F
if
insts_sets.get(op1,
None
)
=
=
None
:
insts_sets[op1]
=
1
else
:
insts_sets[op1]
+
=
1
sorted_dict
=
dict
(
sorted
(insts_sets.items(), key
=
lambda
item: item[
1
], reverse
=
True
))
for
inst, count
in
sorted_dict.items():
print
(f
'op1: {inst}, count: {count}'
)
op1: 23, count: 56
op1: 11, count: 51
op1: 40, count: 38
op1: 21, count: 27
op1: 24, count: 2
op1: 12, count: 2
op1: 17, count: 2
op1: 48, count: 2
op1: 52, count: 1
op1: 7, count: 1
op1: 23, count: 56
op1: 11, count: 51
op1: 40, count: 38
op1: 21, count: 27
op1: 24, count: 2
op1: 12, count: 2
op1: 17, count: 2
op1: 48, count: 2
op1: 52, count: 1
op1: 7, count: 1
import
struct
pcode_start
=
0xB090
pcode_size
=
0x2D8
with
open
(
"libEncryptor.so"
,
"rb"
) as f:
content
=
f.read()
bytes_code
=
content[pcode_start : pcode_start
+
pcode_size]
insts_op1_sets
=
{}
insts_op2_sets
=
{}
for
pc
in
range
(
0
, pcode_size,
4
):
word
=
struct.unpack(
"<I"
, bytes_code[pc : pc
+
4
])
if
len
(word) >
0
:
opcode
=
word[
0
]
op1
=
opcode &
0x3F
if
op1
=
=
11
:
op2
=
(opcode >>
6
) &
0x3F
if
insts_op2_sets.get(op2,
None
)
=
=
None
:
insts_op2_sets[op2]
=
1
else
:
insts_op2_sets[op2]
+
=
1
else
:
if
insts_op1_sets.get(op1,
None
)
=
=
None
:
insts_op1_sets[op1]
=
1
else
:
insts_op1_sets[op1]
+
=
1
print
(
"op1指令统计:"
)
op1_sorted_dict
=
dict
(
sorted
(insts_op1_sets.items(), key
=
lambda
item: item[
1
], reverse
=
True
))
for
inst, count
in
op1_sorted_dict.items():
print
(f
'op1: {inst}, count: {count}'
)
print
(
"op2指令统计:"
)
op2_sorted_dict
=
dict
(
sorted
(insts_op2_sets.items(), key
=
lambda
item: item[
1
], reverse
=
True
))
for
inst, count
in
op2_sorted_dict.items():
print
(f
'op1: 11, op2: {inst}, count: {count}'
)
import
struct
pcode_start
=
0xB090
pcode_size
=
0x2D8
with
open
(
"libEncryptor.so"
,
"rb"
) as f:
content
=
f.read()
bytes_code
=
content[pcode_start : pcode_start
+
pcode_size]
insts_op1_sets
=
{}
insts_op2_sets
=
{}
for
pc
in
range
(
0
, pcode_size,
4
):
word
=
struct.unpack(
"<I"
, bytes_code[pc : pc
+
4
])
if
len
(word) >
0
:
opcode
=
word[
0
]
op1
=
opcode &
0x3F
if
op1
=
=
11
:
op2
=
(opcode >>
6
) &
0x3F
if
insts_op2_sets.get(op2,
None
)
=
=
None
:
insts_op2_sets[op2]
=
1
else
:
insts_op2_sets[op2]
+
=
1
else
:
if
insts_op1_sets.get(op1,
None
)
=
=
None
:
insts_op1_sets[op1]
=
1
else
:
insts_op1_sets[op1]
+
=
1
print
(
"op1指令统计:"
)
op1_sorted_dict
=
dict
(
sorted
(insts_op1_sets.items(), key
=
lambda
item: item[
1
], reverse
=
True
))
for
inst, count
in
op1_sorted_dict.items():
print
(f
'op1: {inst}, count: {count}'
)
print
(
"op2指令统计:"
)
op2_sorted_dict
=
dict
(
sorted
(insts_op2_sets.items(), key
=
lambda
item: item[
1
], reverse
=
True
))
for
inst, count
in
op2_sorted_dict.items():
print
(f
'op1: 11, op2: {inst}, count: {count}'
)
def
decode(pcode_start, pcode_size, liner_disasm
=
False
):
with
open
(
"libEncryptor.so"
,
"rb"
) as f:
content
=
f.read()
print
(f
"{'pc':^8} {'指令':^8} {'op1':^8} {'op2':^8}\t{'助记符':^30}"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx0, #0\t\t\t;x0始终为0,XZR寄存器?"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx4, pArgs\t\t;参数列表指针"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx5, #0"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx6, pfn_external_func_list\t\t;外部函数列表指针"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx7, pCallRegisterTrampolineFunction\t;保存跳转函数地址"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx29, pVirualStackBottom;\t\t;虚拟机堆栈栈底"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tlr, #0\t\t\t;x31=0"
)
known_insns_op1
=
{}
known_insns_op2
=
{}
unknown_insts_op1
=
set
()
unknown_insts_op2
=
set
()
bytes_code
=
content[pcode_start : pcode_start
+
pcode_size]
for
pc
in
range
(
0
, pcode_size,
4
):
word
=
struct.unpack(
"<I"
, bytes_code[pc : pc
+
4
])
asm
=
""
dcode_insns_status
=
0
if
len
(word) >
0
:
opcode
=
word[
0
]
op1
=
get_op1(opcode)
Xt
=
get_openand1(opcode)
Xn
=
get_operand2(opcode)
Xm
=
get_operand3(opcode)
X4
=
get_operand4(opcode)
match op1:
case
11
:
Xt
=
get_operand3(opcode)
Xn
=
get_openand1(opcode)
Xm
=
get_operand2(opcode)
op2
=
get_op2(opcode)
match op2:
case
7
:
dcode_insns_status
=
2
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tORR\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, {get_regsiter_name(Xm)}"
)
case
12
:
dcode_insns_status
=
2
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tADD\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, {get_regsiter_name(Xm)}"
)
case
25
:
dcode_insns_status
=
2
if
X4
=
=
0
:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tNOP\t\t\t\t;LSL\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, #{X4}"
)
else
:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tLSL)\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, #{X4}"
)
case
39
:
dcode_insns_status
=
2
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tCMP\t{get_regsiter_name(Xm)}, {get_regsiter_name(Xn)}"
)
print
(f
"{' '*8} {' '*8} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tCSET\t{get_regsiter_name(Xt)}, CC"
)
case
43
:
dcode_insns_status
=
2
if
liner_disasm:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tBR\t{get_regsiter_name(Xm)}\t\t\t;LR={get_regsiter_name(Xt)}"
)
else
:
asm
=
f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tBR\t{get_regsiter_name(Xm)}\t\t\t;LR={get_regsiter_name(Xt)}"
set_branch_control(asm)
case
62
:
dcode_insns_status
=
2
if
liner_disasm:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tExitVm\t0\t\t\t;{get_regsiter_name(Xm)}"
)
else
:
asm
=
f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tExitVm\t0\t\t\t;{get_regsiter_name(Xm)}"
set_branch_control(asm)
case _:
dcode_insns_status
=
4
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\t>> op2_xxx\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, {get_regsiter_name(Xm)}"
)
case
7
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tORR\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, #{hex(imm16)}"
)
case
12
:
dcode_insns_status
=
1
imm26
=
get_imm26(opcode)
offset
=
imm26
*
4
if
liner_disasm:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tB\t{hex(offset)}"
)
else
:
asm
=
f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tB\t{hex(offset)}"
set_branch_control(asm)
case
17
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tADD\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, #{hex(imm16)}"
)
case
21
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tADD\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, #{hex(imm16)}"
)
case
23
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tSTR\t{get_regsiter_name(Xt)}, [{get_regsiter_name(Xn)}, #{hex(imm16)}]"
)
case
24
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
offset
=
pc
+
imm16
*
4
+
4
if
liner_disasm:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tB.HS\t#{hex(offset)}\t\t\t;{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, ${hex(imm16 * 4)}"
)
else
:
asm
=
f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tB.HS\t#{hex(offset)}\t\t\t;{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, ${hex(imm16 * 4)}"
set_branch_control(asm)
case
40
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tLDR\t{get_regsiter_name(Xt)}, [{get_regsiter_name(Xn)}, #{hex(imm16)}]"
)
case
48
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tSTR\t{get_regsiter_name(Xt, 32)}, [{get_regsiter_name(Xn)}, #{hex(imm16)}]"
)
case
52
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode,
False
)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tMOVZ\t{get_regsiter_name(Xt, 32)}, #{hex(imm16)}, LSL#16"
)
print
(f
"{' '*8} {' '*8} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tSXTW\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xt, 32)}"
)
case _:
dcode_insns_status
=
3
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\t>> op1_xxx\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, {get_regsiter_name(Xm)}"
)
if
not
liner_disasm:
branch_pipeline_process()
record_insns(dcode_insns_status, known_insns_op1, known_insns_op2, unknown_insts_op1, unknown_insts_op2, opcode)
else
:
print
(
"error"
)
decode_statistics(known_insns_op1, known_insns_op2, unknown_insts_op1, unknown_insts_op2)
def
main():
pcode_start
=
0xB090
pcode_size
=
0x2D8
decode(pcode_start, pcode_size)
pcode_start
=
0xBDE0
pcode_size
=
0x1C8
decode(pcode_start, pcode_size)
pcode_start
=
0x85C0
pcode_size
=
0xCC
decode(pcode_start, pcode_size)
if
__name__
=
=
"__main__"
:
main()
def
decode(pcode_start, pcode_size, liner_disasm
=
False
):
with
open
(
"libEncryptor.so"
,
"rb"
) as f:
content
=
f.read()
print
(f
"{'pc':^8} {'指令':^8} {'op1':^8} {'op2':^8}\t{'助记符':^30}"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx0, #0\t\t\t;x0始终为0,XZR寄存器?"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx4, pArgs\t\t;参数列表指针"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx5, #0"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx6, pfn_external_func_list\t\t;外部函数列表指针"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx7, pCallRegisterTrampolineFunction\t;保存跳转函数地址"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tx29, pVirualStackBottom;\t\t;虚拟机堆栈栈底"
)
print
(f
"{'-'*8} {'-'*8} {'-'*8} {'-'*8} MOV\tlr, #0\t\t\t;x31=0"
)
known_insns_op1
=
{}
known_insns_op2
=
{}
unknown_insts_op1
=
set
()
unknown_insts_op2
=
set
()
bytes_code
=
content[pcode_start : pcode_start
+
pcode_size]
for
pc
in
range
(
0
, pcode_size,
4
):
word
=
struct.unpack(
"<I"
, bytes_code[pc : pc
+
4
])
asm
=
""
dcode_insns_status
=
0
if
len
(word) >
0
:
opcode
=
word[
0
]
op1
=
get_op1(opcode)
Xt
=
get_openand1(opcode)
Xn
=
get_operand2(opcode)
Xm
=
get_operand3(opcode)
X4
=
get_operand4(opcode)
match op1:
case
11
:
Xt
=
get_operand3(opcode)
Xn
=
get_openand1(opcode)
Xm
=
get_operand2(opcode)
op2
=
get_op2(opcode)
match op2:
case
7
:
dcode_insns_status
=
2
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tORR\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, {get_regsiter_name(Xm)}"
)
case
12
:
dcode_insns_status
=
2
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tADD\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, {get_regsiter_name(Xm)}"
)
case
25
:
dcode_insns_status
=
2
if
X4
=
=
0
:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tNOP\t\t\t\t;LSL\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, #{X4}"
)
else
:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tLSL)\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, #{X4}"
)
case
39
:
dcode_insns_status
=
2
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tCMP\t{get_regsiter_name(Xm)}, {get_regsiter_name(Xn)}"
)
print
(f
"{' '*8} {' '*8} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tCSET\t{get_regsiter_name(Xt)}, CC"
)
case
43
:
dcode_insns_status
=
2
if
liner_disasm:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tBR\t{get_regsiter_name(Xm)}\t\t\t;LR={get_regsiter_name(Xt)}"
)
else
:
asm
=
f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tBR\t{get_regsiter_name(Xm)}\t\t\t;LR={get_regsiter_name(Xt)}"
set_branch_control(asm)
case
62
:
dcode_insns_status
=
2
if
liner_disasm:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tExitVm\t0\t\t\t;{get_regsiter_name(Xm)}"
)
else
:
asm
=
f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\tExitVm\t0\t\t\t;{get_regsiter_name(Xm)}"
set_branch_control(asm)
case _:
dcode_insns_status
=
4
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {op2:02d}(0x{op2:02X})\t>> op2_xxx\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, {get_regsiter_name(Xm)}"
)
case
7
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tORR\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, #{hex(imm16)}"
)
case
12
:
dcode_insns_status
=
1
imm26
=
get_imm26(opcode)
offset
=
imm26
*
4
if
liner_disasm:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tB\t{hex(offset)}"
)
else
:
asm
=
f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tB\t{hex(offset)}"
set_branch_control(asm)
case
17
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tADD\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, #{hex(imm16)}"
)
case
21
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tADD\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, #{hex(imm16)}"
)
case
23
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tSTR\t{get_regsiter_name(Xt)}, [{get_regsiter_name(Xn)}, #{hex(imm16)}]"
)
case
24
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
offset
=
pc
+
imm16
*
4
+
4
if
liner_disasm:
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tB.HS\t#{hex(offset)}\t\t\t;{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, ${hex(imm16 * 4)}"
)
else
:
asm
=
f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tB.HS\t#{hex(offset)}\t\t\t;{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, ${hex(imm16 * 4)}"
set_branch_control(asm)
case
40
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tLDR\t{get_regsiter_name(Xt)}, [{get_regsiter_name(Xn)}, #{hex(imm16)}]"
)
case
48
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tSTR\t{get_regsiter_name(Xt, 32)}, [{get_regsiter_name(Xn)}, #{hex(imm16)}]"
)
case
52
:
dcode_insns_status
=
1
imm16
=
get_imm16(opcode,
False
)
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tMOVZ\t{get_regsiter_name(Xt, 32)}, #{hex(imm16)}, LSL#16"
)
print
(f
"{' '*8} {' '*8} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\tSXTW\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xt, 32)}"
)
case _:
dcode_insns_status
=
3
print
(f
"{pc:08X} {opcode:08X} {opcode & 0x3F:02d}(0x{opcode & 0x3F:02X}) {'-'*8}\t>> op1_xxx\t{get_regsiter_name(Xt)}, {get_regsiter_name(Xn)}, {get_regsiter_name(Xm)}"
)
if
not
liner_disasm:
branch_pipeline_process()
record_insns(dcode_insns_status, known_insns_op1, known_insns_op2, unknown_insts_op1, unknown_insts_op2, opcode)
else
:
print
(
"error"
)
decode_statistics(known_insns_op1, known_insns_op2, unknown_insts_op1, unknown_insts_op2)
def
main():
pcode_start
=
0xB090
pcode_size
=
0x2D8
decode(pcode_start, pcode_size)
pcode_start
=
0xBDE0
pcode_size
=
0x1C8
decode(pcode_start, pcode_size)
pcode_start
=
0x85C0
pcode_size
=
0xCC
decode(pcode_start, pcode_size)
if
__name__
=
=
"__main__"
:
main()
import
secrets
import
hashlib
from
Crypto.Cipher
import
AES
from
Crypto.Util.Padding
import
pad, unpad
def
generate_rand_number():
return
secrets.token_bytes(
32
)
def
decrypt_seeds():
key1
=
[
0x52
,
0x09
,
0x6A
,
0xD5
,
0x30
,
0x36
,
0xA5
,
0x38
,
0xBF
,
0x40
,
0xA3
,
0x9E
,
0x81
,
0xF3
,
0xD7
,
0xFB
]
key1
+
=
[
0x7C
,
0xE3
,
0x39
,
0x82
,
0x9B
,
0x2F
,
0xFF
,
0x87
,
0x34
,
0x8E
,
0x43
,
0x44
,
0xC4
,
0xDE
,
0xE9
,
0xCB
]
key1
+
=
[
0x54
,
0x7B
,
0x94
,
0x32
,
0xA6
,
0xC2
,
0x23
,
0x3D
,
0xEE
,
0x4C
,
0x95
,
0x0B
,
0x42
,
0xFA
,
0xC3
,
0x4E
]
key1
+
=
[
0x08
,
0x2E
,
0xA1
,
0x66
,
0x28
,
0xD9
,
0x24
,
0xB2
,
0x76
,
0x5B
,
0xA2
,
0x49
,
0x6D
,
0x8B
,
0xD1
,
0x25
]
key2
=
[
0x1F
,
0xDD
,
0xA8
,
0x33
,
0x88
,
0x07
,
0xC7
,
0x31
,
0xB1
,
0x12
,
0x10
,
0x59
,
0x27
,
0x80
,
0xEC
,
0x5F
]
key2
+
=
[
0x60
,
0x51
,
0x7F
,
0xA9
,
0x19
,
0xB5
,
0x4A
,
0x0D
,
0x2D
,
0xE5
,
0x7A
,
0x9F
,
0x93
,
0xC9
,
0x9C
,
0xEF
]
key2
+
=
[
0xA0
,
0xE0
,
0x3B
,
0x4D
,
0xAE
,
0x2A
,
0xF5
,
0xB0
,
0xC8
,
0xEB
,
0xBB
,
0x3C
,
0x83
,
0x53
,
0x99
,
0x61
]
key2
+
=
[
0x17
,
0x2B
,
0x04
,
0x7E
,
0xBA
,
0x77
,
0xD6
,
0x26
,
0xE1
,
0x69
,
0x14
,
0x63
,
0x55
,
0x21
,
0x0C
,
0x7D
]
results
=
bytearray()
for
i
in
range
(
len
(key1)):
results.append(key1[i] ^ key2[i])
return
results
def
sha512(buff):
sha512_hash
=
hashlib.sha512()
sha512_hash.update(buff)
return
sha512_hash.digest()
def
get_aes_key_iv(rand_num):
rand_num_hash
=
sha512(rand_num)
seeds
=
decrypt_seeds()
data
=
rand_num_hash
+
seeds
key_iv_hash
=
sha512(data)
print
(f
"rand_num: {rand_num.hex()}"
)
print
(f
"rand_num_hash: {rand_num_hash.hex()}"
)
print
(f
"seeds: {seeds.hex()}"
)
print
(f
"rand_num_hash + seeds: {data.hex()}"
)
print
(f
"key_iv_hash: {key_iv_hash.hex()}"
)
print
(f
"aes key: {key_iv_hash[0:0x10].hex()}"
)
print
(f
"aes iv: {key_iv_hash[0x10:0x20].hex()}"
)
return
key_iv_hash[
0
:
0x10
], key_iv_hash[
0x10
:
0x20
]
def
aes_128_cbc_encrypt(plaintext, key, iv):
cipher
=
AES.new(key, AES.MODE_CBC, iv)
padded_data
=
pad(plaintext, AES.block_size)
ciphertext
=
cipher.encrypt(padded_data)
return
ciphertext
def
get_magic():
return
b
"\x74\x63\x05\x10\x00\x00"
def
ttEncrypt(buff):
magic
=
get_magic()
rand_number
=
generate_rand_number()
aes_key, aes_iv
=
get_aes_key_iv(rand_number)
buff_hash
=
sha512(buff)
aes_plaintext
=
buff_hash
+
buff
aes_ciphertext
=
aes_128_cbc_encrypt(aes_plaintext, aes_key, aes_iv)
print
(f
"plaintext: {buff.hex()}"
)
print
(f
"rand_number: {rand_number.hex()}"
)
print
(f
"buff hash: {buff_hash.hex()}"
)
print
(f
"aes_plaintext: {aes_plaintext.hex()}"
)
print
(f
"ciphertext: {aes_ciphertext.hex()}"
)
return
magic
+
rand_number
+
aes_ciphertext
def
main():
buff
=
b
'aabbccddeeffgg'
result
=
ttEncrypt(buff)
print
(f
"ttEncrypt: {result.hex()}"
)
def
test_aes():
buff
=
b
"\x61\x02\xbe\x54\xa6\x2a\x73\xe7\x65\xba\x38\xc9\x87\x34\x09\xbd"
+
\
b
"\xeb\xb6\xb0\xd3\x7e\xa0\x60\x40\x3d\x0c\x26\xfe\xa5\xeb\xb6\xba"
+
\
b
"\x5a\x0c\x7f\x36\xec\xb7\x58\xc7\x7e\x19\x37\x50\x5f\xa8\x5b\x4e"
+
\
b
"\x77\xce\x82\x7a\x70\x09\xd2\x2b\x2f\xaf\xc4\x68\x00\xd7\xa9\xff"
+
\
b
"\x62\x69\x61\x6e\x66\x65\x6e\x67"
aes_key
=
b
"\xe8\xaf\x6e\x91\xde\x99\x7e\xf0\xfa\xfb\xcd\xbe\x97\x73\xb2\xc5"
aes_iv
=
b
"\x03\x7e\xed\x97\x4e\x1e\xc5\x19\xdc\xc2\xb4\x35\x5b\x26\xf0\x1b"
ciphertext
=
aes_128_cbc_encrypt(buff, aes_key, aes_iv)
print
(f
"ciphertext: {ciphertext.hex()}"
)
if
__name__
=
=
"__main__"
:
main()
import
secrets
import
hashlib
from
Crypto.Cipher
import
AES
from
Crypto.Util.Padding
import
pad, unpad
def
generate_rand_number():
return
secrets.token_bytes(
32
)
def
decrypt_seeds():
key1
=
[
0x52
,
0x09
,
0x6A
,
0xD5
,
0x30
,
0x36
,
0xA5
,
0x38
,
0xBF
,
0x40
,
0xA3
,
0x9E
,
0x81
,
0xF3
,
0xD7
,
0xFB
]
key1
+
=
[
0x7C
,
0xE3
,
0x39
,
0x82
,
0x9B
,
0x2F
,
0xFF
,
0x87
,
0x34
,
0x8E
,
0x43
,
0x44
,
0xC4
,
0xDE
,
0xE9
,
0xCB
]
key1
+
=
[
0x54
,
0x7B
,
0x94
,
0x32
,
0xA6
,
0xC2
,
0x23
,
0x3D
,
0xEE
,
0x4C
,
0x95
,
0x0B
,
0x42
,
0xFA
,
0xC3
,
0x4E
]
key1
+
=
[
0x08
,
0x2E
,
0xA1
,
0x66
,
0x28
,
0xD9
,
0x24
,
0xB2
,
0x76
,
0x5B
,
0xA2
,
0x49
,
0x6D
,
0x8B
,
0xD1
,
0x25
]
key2
=
[
0x1F
,
0xDD
,
0xA8
,
0x33
,
0x88
,
0x07
,
0xC7
,
0x31
,
0xB1
,
0x12
,
0x10
,
0x59
,
0x27
,
0x80
,
0xEC
,
0x5F
]
key2
+
=
[
0x60
,
0x51
,
0x7F
,
0xA9
,
0x19
,
0xB5
,
0x4A
,
0x0D
,
0x2D
,
0xE5
,
0x7A
,
0x9F
,
0x93
,
0xC9
,
0x9C
,
0xEF
]
key2
+
=
[
0xA0
,
0xE0
,
0x3B
,
0x4D
,
0xAE
,
0x2A
,
0xF5
,
0xB0
,
0xC8
,
0xEB
,
0xBB
,
0x3C
,
0x83
,
0x53
,
0x99
,
0x61
]
key2
+
=
[
0x17
,
0x2B
,
0x04
,
0x7E
,
0xBA
,
0x77
,
0xD6
,
0x26
,
0xE1
,
0x69
,
0x14
,
0x63
,
0x55
,
0x21
,
0x0C
,
0x7D
]
results
=
bytearray()
for
i
in
range
(
len
(key1)):
results.append(key1[i] ^ key2[i])
return
results
def
sha512(buff):
sha512_hash
=
hashlib.sha512()
sha512_hash.update(buff)
return
sha512_hash.digest()
def
get_aes_key_iv(rand_num):
rand_num_hash
=
sha512(rand_num)
seeds
=
decrypt_seeds()
data
=
rand_num_hash
+
seeds
key_iv_hash
=
sha512(data)
print
(f
"rand_num: {rand_num.hex()}"
)
print
(f
"rand_num_hash: {rand_num_hash.hex()}"
)
print
(f
"seeds: {seeds.hex()}"
)
print
(f
"rand_num_hash + seeds: {data.hex()}"
)
print
(f
"key_iv_hash: {key_iv_hash.hex()}"
)
print
(f
"aes key: {key_iv_hash[0:0x10].hex()}"
)
print
(f
"aes iv: {key_iv_hash[0x10:0x20].hex()}"
)
return
key_iv_hash[
0
:
0x10
], key_iv_hash[
0x10
:
0x20
]
def
aes_128_cbc_encrypt(plaintext, key, iv):
cipher
=
AES.new(key, AES.MODE_CBC, iv)
padded_data
=
pad(plaintext, AES.block_size)
ciphertext
=
cipher.encrypt(padded_data)
return
ciphertext
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2024-6-27 15:37
被金罡编辑
,原因:
上传的附件: