-
-
[原创]京麒CTF2024-HarmonyOS移动端Native层逆向
-
发表于: 2024-6-5 06:47 24661
-
找到的工具:HapViewer 发行版 - Gitee.com
鸿蒙逆向目前没有完整的逆向工具所以手动逆向:
先将.hap文件后缀更改为.zip解压后就可以看见.hap的文件结构了!
.abc文件类似于安卓的.dex文件,直接用txt文本打开发现并没有进行加密或者混淆源码直接在里面!
发现需要用utf-8可以解决部分中文乱码!
提取出主要的代码:
这段代码初始化了一个flag提交框!!!
在txt里面找到了判断flag的按钮!!var c = testNapi.check(this.flag, value);
发现这里就有check函数可以判断flag!
发现testNapi那么就可以对标安卓的Native层方法了:16.7:NAPI 加载原理(上) | 《ArkUI实战》
testNapi方法是写在libentry.so文件里!
拖入ida直接开始查找!
先了解鸿蒙的Native层方法注册流程(鸿蒙用的是魔改后的Node.js的原生库ffi-napi):
注册方法:RegisterEntryModule
-》napi_module_register
-》要注册方法的结构体napi_module
发现这个check方法是在这里!
找到check方法!!
这里有很多api特别重要先提前了解一波:
这些api的来源都是js的Node-API,华为用ArkTS又封装了一遍:
问chatgpt就可以知道他们的作用:
在之前找到的源码区:
这些代码就是在ArkTS源码区注册的回调函数,Native层的napi_call_function函数可以通过序号调用这些ArkTs层的代码!
先进行部分分析,最后再汇总分析所有伪代码!
Native层的获取回调函数的函数:
下面分析一下逻辑伪代码:
reg_method_1方法在被找到的那一刻就被执行了,返回值是method_1_ret:
得到执行流程:
ArkTS层注册的回调函数有很多我就截取了部分:
这里是写在ArkTS层的回调函数代码!
发现这些回调函数的id:3,259;0,256;等等...
这里监测环境异常主要是通过检查电池信息是否和预定的数据一样不一样则判定环境异常:
再根据so层的代码分析可以知道:
method_0_ret的返回值必须是非0才可以通过环境监测,这里也就是要求:
依次类推也就可以知道如何绕过环境监测了!
知识连接:OpenHarmony4.0源码解析之电源管理子系统 - 文章 OpenHarmony开发者论坛
写个脚本来看看需要的设置的电池数据,来绕过环境异常检测:
要求的电池环境,成功绕过:
继续分析发现switch里面的加密和switch_case_key的关系特别大,根据交叉引用可以找到相关逻辑:
reg_method_1方法在被找到的那一刻就被执行了,返回值是method_1_ret
根据前面的ArkTS层函数的调用规则可以知道:
用python脚本就是:
根据前面的ArkTS层函数的调用规则可以知道:
第一个值是opcode,第二个值是key
加密流程和密钥;[(3, 1), (0, 100), (4, 10), (7, 0), (5, 101), (8, 1), (1, 3), (6, 50), (2, 2)]
拜读大佬wp,但是奈何大佬的代码跑不起来,而且最终加密后的flag数据对比的位置和加密后的数据也不知道怎么来的,最后无奈放弃QAQ
拜读大佬wp:2024 05.27 jqctf 初赛 wp - LaoGong - 飞书云文档 (feishu.cn)
最后经过大佬的指点终于成功了!!剩下的就是算法学习了!
安装环境:
成功跑出flag,源码在下面:
python:
lib的源码:
最终报错:
解决方案:
arm架构下的伪代码可以发现数据对比!
发现一个ida小技巧:
点击Collapse declarations可以把超长的变量声明缩减成一行!
else
if
( !keyvalue )
// keyvalue==0,method_1_ret被转为int32,传入一个参数
{
//VM整体操作流程序号加4
v40 = targetidx + 4;
//获取bin[i+3]作为整数
napi_create_int32(env, *(bin + targetidx + 3), &int_3_arg);
//调用reg_method_0(bin[i+3])得到返回值——》methodfun_0_ret
napi_call_function(env,
this
,reg_method_0,1,&int_3_arg, &methodfun_0_ret);
//将reg_method_1函数的返回值作为switch_case_key
napi_get_value_int32(env, method_1_ret, &method_1_ret_bool);
// 转为int32
LOBYTE(switch_case_key) = method_1_ret_bool;
}
1. VM整体操作流程序号加4
2. 获取bin[i+3]作为整数
3. 调用reg_method_0(bin[i+3])得到返回值——》methodfun_0_ret
4. 将reg_method_1函数的返回值作为switch_case_key
注:switch_case_key用来加密
else
if
( !keyvalue )
// keyvalue==0,method_1_ret被转为int32,传入一个参数
{
//VM整体操作流程序号加4
v40 = targetidx + 4;
//获取bin[i+3]作为整数
napi_create_int32(env, *(bin + targetidx + 3), &int_3_arg);
//调用reg_method_0(bin[i+3])得到返回值——》methodfun_0_ret
napi_call_function(env,
this
,reg_method_0,1,&int_3_arg, &methodfun_0_ret);
//将reg_method_1函数的返回值作为switch_case_key
napi_get_value_int32(env, method_1_ret, &method_1_ret_bool);
// 转为int32
LOBYTE(switch_case_key) = method_1_ret_bool;
}
1. VM整体操作流程序号加4
2. 获取bin[i+3]作为整数
3. 调用reg_method_0(bin[i+3])得到返回值——》methodfun_0_ret
4. 将reg_method_1函数的返回值作为switch_case_key
注:switch_case_key用来加密
v40 = targetidx + 3;
//VM整体操作流程序号加上3
// keyvalue == 1,method_1_ret返回值被转为utf8,传入一个参数
if
( keyvalue == 1 )
{
//获取bin[i+2]的值作为size
size = *(bin + targetidx + 2);
//获取bin + v40中的字符串,其实就是bin[i+3]
napi_create_string_utf8(env, bin + v40, size, &int_3_arg);
v40 += size;
//VM整体操作流程序号加上字符串的长度
env_1 = env;
//调用reg_method_0函数,将字符串int_3_arg传入reg_method_0函数
napi_call_function(env,
this
, reg_method_0, 1LL, &int_3_arg, &methodfun_0_ret);
//得到返回值reg_method_0函数的返回值
napi_get_value_string_utf8(env, method_1_ret, buf, 128LL, &stringlen1);
if
( stringlen1 )
{
....
}
1. VM整体操作流程序号加上3
2. 获取bin[i+2]的值作为size
3. 获取bin + v40中的字符串,其实就是bin[i+3]
4. VM整体操作流程序号加上字符串的长度
5. 调用reg_method_0函数,将字符串int_3_arg传入reg_method_0函数
6. 得到返回值reg_method_0函数的返回值
v40 = targetidx + 3;
//VM整体操作流程序号加上3
// keyvalue == 1,method_1_ret返回值被转为utf8,传入一个参数
if
( keyvalue == 1 )
{
//获取bin[i+2]的值作为size
size = *(bin + targetidx + 2);
//获取bin + v40中的字符串,其实就是bin[i+3]
napi_create_string_utf8(env, bin + v40, size, &int_3_arg);
v40 += size;
//VM整体操作流程序号加上字符串的长度
env_1 = env;
//调用reg_method_0函数,将字符串int_3_arg传入reg_method_0函数
napi_call_function(env,
this
, reg_method_0, 1LL, &int_3_arg, &methodfun_0_ret);
//得到返回值reg_method_0函数的返回值
napi_get_value_string_utf8(env, method_1_ret, buf, 128LL, &stringlen1);
if
( stringlen1 )
{
....
}
1. VM整体操作流程序号加上3
2. 获取bin[i+2]的值作为size
3. 获取bin + v40中的字符串,其实就是bin[i+3]
4. VM整体操作流程序号加上字符串的长度
5. 调用reg_method_0函数,将字符串int_3_arg传入reg_method_0函数
6. 得到返回值reg_method_0函数的返回值
if
( keyvalue == 2 )
// keyvalue == 2,method_1_ret的返回值被转为bool,传入一个参数
{
//获取bin[i+3]的值作为int_3_arg
napi_create_int32(env, *(bin + targetidx + 3), &int_3_arg);
//转换类型int32-》bool
napi_coerce_to_bool(env, int_3_arg, &int_3_arg);
//调用reg_method_0(int_3_arg)->返回值methodfun_0_ret
napi_call_function(env,
this
, reg_method_0, 1LL, &int_3_arg, &methodfun_0_ret);
//将reg_method_1函数的返回值作为switch_case_key
napi_get_value_bool(env, method_1_ret, &method_1_ret_bool);
LOBYTE(switch_case_key) = method_1_ret_bool;
v40 = targetidx + 4;
}
1. 获取bin[i+3]的值作为int_3_arg
2. 转换类型int32-》
bool
3. 调用reg_method_0(int_3_arg)
4. 将reg_method_1函数的返回值作为switch_case_key
注:switch_case_key用来加密
if
( keyvalue == 2 )
// keyvalue == 2,method_1_ret的返回值被转为bool,传入一个参数
{
//获取bin[i+3]的值作为int_3_arg
napi_create_int32(env, *(bin + targetidx + 3), &int_3_arg);
//转换类型int32-》bool
napi_coerce_to_bool(env, int_3_arg, &int_3_arg);
//调用reg_method_0(int_3_arg)->返回值methodfun_0_ret
napi_call_function(env,
this
, reg_method_0, 1LL, &int_3_arg, &methodfun_0_ret);
//将reg_method_1函数的返回值作为switch_case_key
napi_get_value_bool(env, method_1_ret, &method_1_ret_bool);
LOBYTE(switch_case_key) = method_1_ret_bool;
v40 = targetidx + 4;
}
1. 获取bin[i+3]的值作为int_3_arg
2. 转换类型int32-》
bool
3. 调用reg_method_0(int_3_arg)
4. 将reg_method_1函数的返回值作为switch_case_key
注:switch_case_key用来加密
def
dump_bin(
bin
):
d
=
[]
pc
=
0
while
pc <
len
(
bin
):
op
=
bin
[pc]
print
(
'####################'
, pc, op)
# 获取函数地址reg_method_0,通过bin[pc]查找
# print('reg_method_0 = func[%d]' % (op))
# 获取函数地址reg_method_1,通过bin[pc] | 0x100 查找
#调用reg_method_1获得返回值
print
(
'method_1_ret = call func[%d]'
%
(op |
0x100
))
#获取操作类型
type
=
bin
[pc
+
1
]
if
type
=
=
0
:
print
(
'method_0_ret = call func[%d](%d)'
%
(op,
bin
[pc
+
3
]))
key
=
bin
[pc
+
3
]
pc
+
=
4
elif
type
=
=
1
:
#获取bin中字符串的长度
size
=
bin
[pc
+
2
]
s
=
bin
[pc
+
3
: pc
+
3
+
size]
print
(
'method_0_ret = call func[%d](%s)'
%
(op,
repr
(s)))
pc
+
=
3
+
size
elif
type
=
=
2
:
print
(
'method_0_ret = call func[%d](%d)'
%
(op,
bin
[pc
+
3
]))
key
=
bin
[pc
+
3
]
pc
+
=
4
else
:
pc
+
=
3
assert
False
d.append((op, key))
return
d
with
open
(r
'.\bin'
,
'rb'
) as
file
:
encrypted_data
=
file
.read()
print
(dump_bin(encrypted_data))
def
dump_bin(
bin
):
d
=
[]
pc
=
0
while
pc <
len
(
bin
):
op
=
bin
[pc]
print
(
'####################'
, pc, op)
# 获取函数地址reg_method_0,通过bin[pc]查找
# print('reg_method_0 = func[%d]' % (op))
# 获取函数地址reg_method_1,通过bin[pc] | 0x100 查找
#调用reg_method_1获得返回值
print
(
'method_1_ret = call func[%d]'
%
(op |
0x100
))
#获取操作类型
type
=
bin
[pc
+
1
]
if
type
=
=
0
:
print
(
'method_0_ret = call func[%d](%d)'
%
(op,
bin
[pc
+
3
]))
key
=
bin
[pc
+
3
]
pc
+
=
4
elif
type
=
=
1
:
#获取bin中字符串的长度
size
=
bin
[pc
+
2
]
s
=
bin
[pc
+
3
: pc
+
3
+
size]
print
(
'method_0_ret = call func[%d](%s)'
%
(op,
repr
(s)))
pc
+
=
3
+
size
elif
type
=
=
2
:
print
(
'method_0_ret = call func[%d](%d)'
%
(op,
bin
[pc
+
3
]))
key
=
bin
[pc
+
3
]
pc
+
=
4
else
:
pc
+
=
3
assert
False
d.append((op, key))
return
d
with
open
(r
'.\bin'
,
'rb'
) as
file
:
encrypted_data
=
file
.read()
print
(dump_bin(encrypted_data))
#################### 0 3
method_1_ret = call func[259]
method_0_ret = call func[3](1)
#################### 4 0
method_1_ret = call func[256]
method_0_ret = call func[0](100)
#################### 8 4
method_1_ret = call func[260]
method_0_ret = call func[4](10)
#################### 12 7
method_1_ret = call func[263]
method_0_ret = call func[7](0)
#################### 16 5
method_1_ret = call func[261]
method_0_ret = call func[5](b
'hackers'
)
#################### 26 8
method_1_ret = call func[264]
method_0_ret = call func[8](1)
#################### 30 1
method_1_ret = call func[257]
method_0_ret = call func[1](3)
#################### 34 6
method_1_ret = call func[262]
method_0_ret = call func[6](50)
#################### 38 2
method_1_ret = call func[258]
method_0_ret = call func[2](2)
#################### 0 3
method_1_ret = call func[259]
method_0_ret = call func[3](1)
#################### 4 0
method_1_ret = call func[256]
method_0_ret = call func[0](100)
#################### 8 4
method_1_ret = call func[260]
method_0_ret = call func[4](10)
#################### 12 7
method_1_ret = call func[263]
method_0_ret = call func[7](0)
#################### 16 5
method_1_ret = call func[261]
method_0_ret = call func[5](b
'hackers'
)
#################### 26 8
method_1_ret = call func[264]
method_0_ret = call func[8](1)
#################### 30 1
method_1_ret = call func[257]
method_0_ret = call func[1](3)
#################### 34 6
method_1_ret = call func[262]
method_0_ret = call func[6](50)
#################### 38 2
method_1_ret = call func[258]
method_0_ret = call func[2](2)
method_1_ret = call func[259]
// 直接返回电池插入类型
testNapi.
register
(259, () => {
return
batteryInfo.pluggedType;
});
method_0_ret = call func[3](1)
// 电池插入类型差值判断
testNapi.
register
(3, (a) => {
var t = batteryInfo.pluggedType - a;
var f;
if
(t > 0)
f = 1;
else
if
(t == 0)
f = 0;
else
f = -1;
return
f === 0;
});
method_1_ret = call func[259]
// 直接返回电池插入类型
testNapi.
register
(259, () => {
return
batteryInfo.pluggedType;
});
method_0_ret = call func[3](1)
// 电池插入类型差值判断
testNapi.
register
(3, (a) => {
var t = batteryInfo.pluggedType - a;
var f;
if
(t > 0)
f = 1;
else
if
(t == 0)
f = 0;
else
f = -1;
return
f === 0;
});
batteryInfo.pluggedType 的值等于 1 就可以通过环境检查!!
batteryInfo.pluggedType 的值等于 1 就可以通过环境检查!!
def
dump_bin(
bin
):
d
=
[]
pc
=
0
while
pc <
len
(
bin
):
op
=
bin
[pc]
print
(
'------------->'
, pc, op)
# 获取函数地址reg_method_0,通过bin[pc]查找
# print('reg_method_0 = func[%d]' % (op))
# 获取函数地址reg_method_1,通过bin[pc] | 0x100 查找
#调用reg_method_1获得返回值
print
(
'method_1_ret = call func[%d]'
%
(op |
0x100
))
if
(op |
0x100
)
=
=
256
:
print
(
"batteryInfo.batterySOC:"
,end
=
"")
elif
(op |
0x100
)
=
=
257
:
print
(
"batteryInfo.chargingStatus:"
,end
=
"")
elif
(op |
0x100
)
=
=
258
:
print
(
"batteryInfo.healthStatus:"
,end
=
"")
elif
(op |
0x100
)
=
=
259
:
print
(
"batteryInfo.pluggedType:"
,end
=
"")
elif
(op |
0x100
)
=
=
260
:
print
(
"batteryInfo.voltage:"
,end
=
"")
elif
(op |
0x100
)
=
=
261
:
print
(
"batteryInfo.technology:"
,end
=
"")
elif
(op |
0x100
)
=
=
262
:
print
(
"batteryInfo.batteryTemperature:"
,end
=
"")
elif
(op |
0x100
)
=
=
263
:
print
(
"batteryInfo.isBatteryPresent:"
,end
=
"")
elif
(op |
0x100
)
=
=
264
:
print
(
"batteryInfo.batteryCapacityLevel:"
,end
=
"")
#获取操作类型
type
=
bin
[pc
+
1
]
if
type
=
=
0
:
print
(
bin
[pc
+
3
])
print
(
'method_0_ret = call func[%d](%d)'
%
(op,
bin
[pc
+
3
]))
key
=
bin
[pc
+
3
]
pc
+
=
4
elif
type
=
=
1
:
#获取bin中字符串的长度
size
=
bin
[pc
+
2
]
s
=
bin
[pc
+
3
: pc
+
3
+
size]
print
(
repr
(s))
print
(
'method_0_ret = call func[%d](%s)'
%
(op,
repr
(s)))
pc
+
=
3
+
size
elif
type
=
=
2
:
print
(
bin
[pc
+
3
])
print
(
'method_0_ret = call func[%d](%d)'
%
(op,
bin
[pc
+
3
]))
key
=
bin
[pc
+
3
]
pc
+
=
4
else
:
pc
+
=
3
assert
False
d.append((op, key))
return
d
with
open
(r
'.\bin'
,
'rb'
) as
file
:
encrypted_data
=
file
.read()
print
(dump_bin(encrypted_data))
def
dump_bin(
bin
):
d
=
[]
pc
=
0
while
pc <
len
(
bin
):
op
=
bin
[pc]
print
(
'------------->'
, pc, op)
# 获取函数地址reg_method_0,通过bin[pc]查找
# print('reg_method_0 = func[%d]' % (op))
# 获取函数地址reg_method_1,通过bin[pc] | 0x100 查找
#调用reg_method_1获得返回值
print
(
'method_1_ret = call func[%d]'
%
(op |
0x100
))
if
(op |
0x100
)
=
=
256
:
print
(
"batteryInfo.batterySOC:"
,end
=
"")
elif
(op |
0x100
)
=
=
257
:
print
(
"batteryInfo.chargingStatus:"
,end
=
"")
elif
(op |
0x100
)
=
=
258
:
print
(
"batteryInfo.healthStatus:"
,end
=
"")
elif
(op |
0x100
)
=
=
259
:
print
(
"batteryInfo.pluggedType:"
,end
=
"")
elif
(op |
0x100
)
=
=
260
:
print
(
"batteryInfo.voltage:"
,end
=
"")
elif
(op |
0x100
)
=
=
261
:
print
(
"batteryInfo.technology:"
,end
=
"")
elif
(op |
0x100
)
=
=
262
:
print
(
"batteryInfo.batteryTemperature:"
,end
=
"")
elif
(op |
0x100
)
=
=
263
:
print
(
"batteryInfo.isBatteryPresent:"
,end
=
"")
elif
(op |
0x100
)
=
=
264
:
print
(
"batteryInfo.batteryCapacityLevel:"
,end
=
"")
#获取操作类型
type
=
bin
[pc
+
1
]
if
type
=
=
0
:
print
(
bin
[pc
+
3
])
print
(
'method_0_ret = call func[%d](%d)'
%
(op,
bin
[pc
+
3
]))
key
=
bin
[pc
+
3
]
pc
+
=
4
elif
type
=
=
1
:
#获取bin中字符串的长度
size
=
bin
[pc
+
2
]
s
=
bin
[pc
+
3
: pc
+
3
+
size]
print
(
repr
(s))
print
(
'method_0_ret = call func[%d](%s)'
%
(op,
repr
(s)))
pc
+
=
3
+
size
elif
type
=
=
2
:
print
(
bin
[pc
+
3
])
print
(
'method_0_ret = call func[%d](%d)'
%
(op,
bin
[pc
+
3
]))
key
=
bin
[pc
+
3
]
pc
+
=
4
else
:
pc
+
=
3
assert
False
d.append((op, key))
return
d
with
open
(r
'.\bin'
,
'rb'
) as
file
:
encrypted_data
=
file
.read()
print
(dump_bin(encrypted_data))
do
{
if
valuekey == 0:
switch_case_key...
if
valuekey == 1:
switch_case_key...
if
valuekey == 2:
switch_case_key...
....
switch
( bin_i )
{
case
0:
....
v54 = switch_case_key & 0x3F | (switch_case_key >> 1) & 0x40 | (2 * switch_case_key) & 0x80;
....
case
1:
.....
case
8:
....
}
}
while
( v40 < bin_len );
do
{
if
valuekey == 0:
switch_case_key...
if
valuekey == 1:
switch_case_key...
if
valuekey == 2:
switch_case_key...
....
switch
( bin_i )
{
case
0:
....
v54 = switch_case_key & 0x3F | (switch_case_key >> 1) & 0x40 | (2 * switch_case_key) & 0x80;
....
case
1:
.....
case
8:
....
}
}
while
( v40 < bin_len );
else
if
( !keyvalue )
// keyvalue==0,method_1_ret被转为int32,传入一个参数
{
v40 = targetidx + 4;
napi_create_int32(env, *(bin + targetidx + 3), &int_3_arg);
napi_call_function(env,
this
, reg_method_0, 1LL, &int_3_arg, &methodfun_0_ret);
napi_get_value_int32(env, method_1_ret, &method_1_ret_bool);
// 转为int32
LOBYTE(switch_case_key) = method_1_ret_bool;
}
else
if
( !keyvalue )
// keyvalue==0,method_1_ret被转为int32,传入一个参数
{
v40 = targetidx + 4;
napi_create_int32(env, *(bin + targetidx + 3), &int_3_arg);
napi_call_function(env,
this
, reg_method_0, 1LL, &int_3_arg, &methodfun_0_ret);
napi_get_value_int32(env, method_1_ret, &method_1_ret_bool);
// 转为int32
LOBYTE(switch_case_key) = method_1_ret_bool;
}
op
=
bin
[pc]
type
=
bin
[pc
+
1
]
if
type
=
=
0
:
key
=
bin
[pc
+
3
]
pc
+
=
4
op
=
bin
[pc]
type
=
bin
[pc
+
1
]
if
type
=
=
0
:
key
=
bin
[pc
+
3
]
pc
+
=
4
if
( keyvalue == 1 )
// keyvalue == 1,method_1_ret返回值被转为utf8,传入一个参数
{
size = *(bin + targetidx + 2);
napi_create_string_utf8(env, bin + v40, size, &int_3_arg);
v40 += size;
env_1 = env;
napi_call_function(env,
this
, reg_method_0, 1LL, &int_3_arg, &methodfun_0_ret);
napi_get_value_string_utf8(env, method_1_ret, buf, 128LL, &stringlen1);
if
( stringlen1 )
{
if
( stringlen1 < 0x20 )
{
idx1 = 0LL;
switch_case_key = 0;
goto
LABEL_56;
}
idx1 = stringlen1 & 0xFFFFFFFFFFFFFFE0LL;
if
( (stringlen1 & 0xFFFFFFFFFFFFFFE0LL) - 32 >= 0x60 )
{
....
while
( stringlen1 != idx1 )
LABEL_56:
LOBYTE(switch_case_key) = buf[idx1++] ^ switch_case_key;
}
else
{
switch_case_key = 0;
}
}
if
( keyvalue == 1 )
// keyvalue == 1,method_1_ret返回值被转为utf8,传入一个参数
{
size = *(bin + targetidx + 2);
napi_create_string_utf8(env, bin + v40, size, &int_3_arg);
v40 += size;
env_1 = env;
napi_call_function(env,
this
, reg_method_0, 1LL, &int_3_arg, &methodfun_0_ret);
napi_get_value_string_utf8(env, method_1_ret, buf, 128LL, &stringlen1);
if
( stringlen1 )
{
if
( stringlen1 < 0x20 )
{
idx1 = 0LL;
switch_case_key = 0;
goto
LABEL_56;
}
idx1 = stringlen1 & 0xFFFFFFFFFFFFFFE0LL;
if
( (stringlen1 & 0xFFFFFFFFFFFFFFE0LL) - 32 >= 0x60 )
{
....
while
( stringlen1 != idx1 )
LABEL_56:
LOBYTE(switch_case_key) = buf[idx1++] ^ switch_case_key;
}
else
{
switch_case_key = 0;
}
}
while
( stringlen1 != idx1 )
LOBYTE(switch_case_key) = buf[idx1++] ^ switch_case_key;
while
( stringlen1 != idx1 )
LOBYTE(switch_case_key) = buf[idx1++] ^ switch_case_key;
op
=
bin
[pc]
type
=
bin
[pc
+
1
]
elif
type
=
=
1
:
size
=
bin
[pc
+
2
]
s
=
bin
[pc
+
3
: pc
+
3
+
size]
key
=
0
for
i
in
s: key ^
=
i
pc
+
=
3
+
size
op
=
bin
[pc]
type
=
bin
[pc
+
1
]
elif
type
=
=
1
:
size
=
bin
[pc
+
2
]
s
=
bin
[pc
+
3
: pc
+
3
+
size]
key
=
0
for
i
in
s: key ^
=
i
pc
+
=
3
+
size
if
( keyvalue == 2 )
// keyvalue == 2,method_1_ret的返回值被转为bool,传入一个参数
{
napi_create_int32(env, *(bin + targetidx + 3), &int_3_arg);
napi_coerce_to_bool(env, int_3_arg, &int_3_arg);
napi_call_function(env,
this
, reg_method_0, 1LL, &int_3_arg, &methodfun_0_ret);
napi_get_value_bool(env, method_1_ret, &method_1_ret_bool);
LOBYTE(switch_case_key) = method_1_ret_bool;
v40 = targetidx + 4;
}
if
( keyvalue == 2 )
// keyvalue == 2,method_1_ret的返回值被转为bool,传入一个参数
{
napi_create_int32(env, *(bin + targetidx + 3), &int_3_arg);
napi_coerce_to_bool(env, int_3_arg, &int_3_arg);
napi_call_function(env,
this
, reg_method_0, 1LL, &int_3_arg, &methodfun_0_ret);
napi_get_value_bool(env, method_1_ret, &method_1_ret_bool);
LOBYTE(switch_case_key) = method_1_ret_bool;
v40 = targetidx + 4;
}
op
=
bin
[pc]
type
=
bin
[pc
+
1
]
if
type
=
=
2
:
key
=
bin
[pc
+
3
]
pc
+
=
4
op
=
bin
[pc]
type
=
bin
[pc
+
1
]
if
type
=
=
2
:
key
=
bin
[pc
+
3
]
pc
+
=
4
def
dump_bin(
bin
):
d
=
[]
pc
=
0
while
pc <
len
(
bin
):
op
=
bin
[pc]
type
=
bin
[pc
+
1
]
if
type
=
=
2
or
type
=
=
0
:
key
=
bin
[pc
+
3
]
pc
+
=
4
elif
type
=
=
1
:
size
=
bin
[pc
+
2
]
s
=
bin
[pc
+
3
: pc
+
3
+
size]
key
=
0
for
i
in
s: key ^
=
i
pc
+
=
3
+
size
else
:
pc
+
=
3
assert
False
d.append((op, key))
return
d
with
open
(r
'.\bin'
,
'rb'
) as
file
:
encrypted_data
=
file
.read()
print
(dump_bin(encrypted_data))
# [(3, 1), (0, 100), (4, 10), (7, 0), (5, 101), (8, 1), (1, 3), (6, 50), (2, 2)]
def
dump_bin(
bin
):
d
=
[]
pc
=
0
while
pc <
len
(
bin
):
op
=
bin
[pc]
type
=
bin
[pc
+
1
]
if
type
=
=
2
or
type
=
=
0
:
key
=
bin
[pc
+
3
]
pc
+
=
4
elif
type
=
=
1
:
size
=
bin
[pc
+
2
]
s
=
bin
[pc
+
3
: pc
+
3
+
size]
key
=
0
for
i
in
s: key ^
=
i
pc
+
=
3
+
size
else
:
pc
+
=
3
assert
False
d.append((op, key))
return
d
with
open
(r
'.\bin'
,
'rb'
) as
file
:
encrypted_data
=
file
.read()
print
(dump_bin(encrypted_data))
# [(3, 1), (0, 100), (4, 10), (7, 0), (5, 101), (8, 1), (1, 3), (6, 50), (2, 2)]
def
dump_bin(
bin
):
d
=
[]
pc
=
0
while
pc <
len
(
bin
):
op
=
bin
[pc]
# print('#', pc, op)
# print('b = func[%d]()' % (op | 0x100))
type
=
bin
[pc
+
1
]
if
type
=
=
2
or
type
=
=
0
:
# missing bin[pc + 2]
# print('a = func[%d](%d)' % (op, bin[pc + 3]))
key
=
bin
[pc
+
3
]
pc
+
=
4
elif
type
=
=
1
:
size
=
bin
[pc
+
2
]
s
=
bin
[pc
+
3
: pc
+
3
+
size]
# print('a = func[%d](%s)' % (op, repr(s)))
# print('b = xor(b)')
key
=
0
for
i
in
s: key ^
=
i
pc
+
=
3
+
size
else
:
pc
+
=
3
assert
False
d.append((op, key))
return
d
def
g(x, n):
return
(x >> n) &
1
def
s(x, n):
return
(x &
1
) << n
def
swapbit(x, m, n):
if
m
=
=
n:
return
x
return
s(g(x, m), n) | s(g(x, n), m) | (x & ~(s(
1
, n) | s(
1
, m)))
def
swapkeep(x, mask):
swapbits
=
~mask &
0xff
m
=
swapbits.bit_length()
-
1
assert
0
<
=
m <
8
swapbits ^
=
1
<< m
n
=
swapbits.bit_length()
-
1
assert
0
<
=
n <
8
swapbits ^
=
1
<< n
assert
swapbits
=
=
0
return
swapbit(x, m, n)
def
ror1(x, n):
n &
=
7
if
isinstance
(x,
int
):
x &
=
0xff
return
(x >> n) | (x << (
8
-
n)) &
0xff
else
:
return
LShR(x, n) | (x << (
8
-
n)) &
0xff
entries
=
[
0x2efa
,
0x42e9
,
0x3428
,
0x38fd
,
0x2522
,
0x480d
,
0x4cc6
,
0x3df6
,
0x51df
]
bin
=
open
(
'./bin'
,
'rb'
).read()
_seq
=
dump_bin(
bin
)
# print(_seq)
import
ctypes
lib
=
ctypes.cdll.LoadLibrary(
'./lib'
)
# extern void setup();
lib.setup()
def
encrypt(array, seq):
for
op, key
in
seq:
for
i
in
range
(
38
):
v
=
lib.bf_round(key, entries[op], i)
type
, val0, val1
=
v >>
16
, (v >>
8
) &
0xff
, v &
0xff
if
type
=
=
0
:
assert
val0
=
=
0
# print(i, 'c ^= 0x%x' % val1)
array[i] ^
=
val1
elif
type
=
=
1
:
# print(i, 'c = ror1(c, %d) ^ 0x%x' % (val0, val1))
array[i]
=
ror1(array[i], val0) ^ val1
elif
type
=
=
2
:
# print(i, 'c = swapkeep(c, 0x%x) ^ 0x%x' % (val0, val1))
array[i]
=
swapkeep(array[i], val0) ^ val1
else
:
assert
False
,
type
from
z3
import
*
_array
=
[BitVec(
'x%d'
%
i,
8
)
for
i
in
range
(
38
)]
array
=
_array[:]
encrypt(array, _seq)
result
=
[
226
,
125
,
77
,
72
,
55
,
231
,
235
,
154
,
118
,
5
,
125
,
135
,
49
,
162
,
160
,
77
,
248
,
159
,
61
,
164
,
56
,
139
,
225
,
229
,
136
,
139
,
89
,
191
,
4
,
222
,
40
,
234
,
126
,
202
,
215
,
252
,
133
,
165
]
# print(len(result))
s
=
Solver()
for
i
in
range
(
38
):
s.add(array[i]
=
=
result[i])
assert
s.check()
=
=
sat
model
=
s.model()
# print(model)
flag
=
[]
for
i
in
_array:
flag.append(model[i].as_long())
print
(bytes(flag))
# flag{3da8767cfb9424b9bbcc09008e36642d}
def
dump_bin(
bin
):
d
=
[]
pc
=
0
while
pc <
len
(
bin
):
op
=
bin
[pc]
# print('#', pc, op)
# print('b = func[%d]()' % (op | 0x100))
type
=
bin
[pc
+
1
]
if
type
=
=
2
or
type
=
=
0
:
# missing bin[pc + 2]
# print('a = func[%d](%d)' % (op, bin[pc + 3]))
key
=
bin
[pc
+
3
]
pc
+
=
4
elif
type
=
=
1
:
size
=
bin
[pc
+
2
]
s
=
bin
[pc
+
3
: pc
+
3
+
size]
# print('a = func[%d](%s)' % (op, repr(s)))
# print('b = xor(b)')
key
=
0
for
i
in
s: key ^
=
i
pc
+
=
3
+
size
else
:
pc
+
=
3
assert
False
d.append((op, key))
return
d
def
g(x, n):
return
(x >> n) &
1
def
s(x, n):
return
(x &
1
) << n
def
swapbit(x, m, n):
if
m
=
=
n:
return
x
return
s(g(x, m), n) | s(g(x, n), m) | (x & ~(s(
1
, n) | s(
1
, m)))
def
swapkeep(x, mask):
swapbits
=
~mask &
0xff
m
=
swapbits.bit_length()
-
1
assert
0
<
=
m <
8
swapbits ^
=
1
<< m
n
=
swapbits.bit_length()
-
1
assert
0
<
=
n <
8
swapbits ^
=
1
<< n
assert
swapbits
=
=
0
return
swapbit(x, m, n)
def
ror1(x, n):
n &
=
7
if
isinstance
(x,
int
):
x &
=
0xff
return
(x >> n) | (x << (
8
-
n)) &
0xff
else
:
return
LShR(x, n) | (x << (
8
-
n)) &
0xff
entries
=
[
0x2efa
,
0x42e9
,
0x3428
,
0x38fd
,
0x2522
,
0x480d
,
0x4cc6
,
0x3df6
,
0x51df
]
bin
=
open
(
'./bin'
,
'rb'
).read()
_seq
=
dump_bin(
bin
)
# print(_seq)
import
ctypes
lib
=
ctypes.cdll.LoadLibrary(
'./lib'
)
# extern void setup();
lib.setup()
def
encrypt(array, seq):
for
op, key
in
seq:
for
i
in
range
(
38
):
v
=
lib.bf_round(key, entries[op], i)
type
, val0, val1
=
v >>
16
, (v >>
8
) &
0xff
, v &
0xff
if
type
=
=
0
:
assert
val0
=
=
0
# print(i, 'c ^= 0x%x' % val1)
array[i] ^
=
val1
elif
type
=
=
1
:
# print(i, 'c = ror1(c, %d) ^ 0x%x' % (val0, val1))
array[i]
=
ror1(array[i], val0) ^ val1
elif
type
=
=
2
:
# print(i, 'c = swapkeep(c, 0x%x) ^ 0x%x' % (val0, val1))
array[i]
=
swapkeep(array[i], val0) ^ val1
else
:
assert
False
,
type
from
z3
import
*
_array
=
[BitVec(
'x%d'
%
i,
8
)
for
i
in
range
(
38
)]
array
=
_array[:]
encrypt(array, _seq)
result
=
[
226
,
125
,
77
,
72
,
55
,
231
,
235
,
154
,
118
,
5
,
125
,
135
,
49
,
162
,
160
,
77
,
248
,
159
,
61
,
164
,
56
,
139
,
225
,
229
,
136
,
139
,
89
,
191
,
4
,
222
,
40
,
234
,
126
,
202
,
215
,
252
,
133
,
165
]
# print(len(result))
s
=
Solver()
for
i
in
range
(
38
):
s.add(array[i]
=
=
result[i])
assert
s.check()
=
=
sat
model
=
s.model()
# print(model)
flag
=
[]
for
i
in
_array:
flag.append(model[i].as_long())
print
(bytes(flag))
# flag{3da8767cfb9424b9bbcc09008e36642d}
#include <stdio.h>
#include <dlfcn.h>
#include <string.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#define ERROR 0
#define WARNING 1
#define INFO 2
#define DEBUG 3
#define VERBOSE 4
const
char
* LOG_LEVEL_CHARS =
"EWIDV"
;
const
char
* LOG_LEVEL_COLORS[] = {
"\x1b[31m"
,
"\x1b[33m"
,
"\x1b[32m"
,
"\x1b[0m"
,
"\x1b[34m"
,
};
int
_log_level = INFO;
int
_log_color = 1;
void
set_log_level(
int
log_level) {
if
(log_level < 0) log_level = 0;
if
(log_level > 4) log_level = 4;
_log_level = log_level;
}
void
set_log_color(
int
log_color) {
_log_color = log_color;
}
void
Log(
int
log_level,
const
char
* format, ...) {
if
(log_level < 0) log_level = 0;
if
(log_level > 4) log_level = 4;
if
(log_level > _log_level)
return
;
if
(_log_color)
printf
(
"%s"
, LOG_LEVEL_COLORS[log_level]);
printf
(
"[%c] "
, LOG_LEVEL_CHARS[log_level]);
va_list
args;
va_start
(args, format);
vprintf
(format, args);
va_end
(args);
if
(_log_color)
printf
(
"\x1b[0m"
);
}
#define LOGE(format, ...) Log(ERROR, format, ##__VA_ARGS__)
#define LOGW(format, ...) Log(WARNING, format, ##__VA_ARGS__)
#define LOGI(format, ...) Log(INFO, format, ##__VA_ARGS__)
#define LOGD(format, ...) Log(DEBUG, format, ##__VA_ARGS__)
#define LOGV(format, ...) Log(VERBOSE, format, ##__VA_ARGS__)
// default info
#define SET_LOGE() set_log_level(ERROR)
#define SET_LOGW() set_log_level(WARNING)
#define SET_LOGI() set_log_level(INFO)
#define SET_LOGD() set_log_level(DEBUG)
#define SET_LOGV() set_log_level(VERBOSE)
// default on
#define SET_LOGCOLOR_OFF() set_log_color(0)
#define SET_LOGCOLOR_ON() set_log_color(1)
#define R_NONE 0
#define R_COPY 5
#define R_GLOB_DAT 6
#define R_JUMP_SLOT 7
#define R_RELATIVE 8
#define R_IRELATIVE 37
typedef
unsigned
char
uchar;
typedef
unsigned
short
ushort;
typedef
unsigned
int
uint;
typedef
unsigned
long
long
ullong;
typedef
struct
{
uchar e_ident[16];
ushort e_type;
ushort e_machine;
uint e_version;
size_t
e_entry;
size_t
e_phoff;
size_t
e_shoff;
uint e_flags;
ushort e_ehsize;
ushort e_phentsize;
ushort e_phnum;
ushort e_shentsize;
ushort e_shnum;
ushort e_shtrndx;
} elf_header;
typedef
struct
{
size_t
d_tag;
size_t
d_un;
} elf_dyn;
typedef
struct
{
size_t
r_offset;
size_t
r_info;
} elf_rel;
typedef
struct
{
size_t
r_offset;
size_t
r_info;
size_t
r_addend;
} elf_rela;
// elf_sym.st_info
#define elf_st_bind(info) ((info) >> 4)
#define elf_st_type(info) ((info) & 0xf)
typedef
struct
{
uint p_type;
uint p_flags;
size_t
p_offset;
size_t
p_vaddr;
size_t
p_paddr;
size_t
p_filesz;
size_t
p_memsz;
size_t
p_align;
} elf_program_header;
typedef
struct
{
uint st_name;
uchar st_info;
uchar st_other;
ushort shndx;
size_t
st_value;
size_t
st_size;
} elf_sym;
// elf_rel[a].r_info
#define elf_r_sym(info) ((info) >> 32)
#define elf_r_type(info) ((uint) (info))
int
do_reloc(
void
* base,
size_t
offset,
size_t
info,
size_t
addend,
const
elf_sym* symtab,
const
char
* strtab) {
#define sym (elf_r_sym(info))
#define type (elf_r_type(info))
#define value (symtab[sym].st_value)
#define size (symtab[sym].st_size)
#define name (strtab + symtab[sym].st_name)
switch
(type) {
case
R_NONE:
break
;
case
R_COPY:
if
(value) {
memcpy
((
void
*) ((
size_t
) base + offset), (
const
void
*) ((
size_t
) base + value), size);
}
else
{
const
void
* sym_value = dlsym((
void
*) -1, name);
// RTLD_DEFAULT
if
(!sym_value) {
LOGW(
"failed to resolve symbol `%s'.\n"
, name);
break
;
}
memcpy
((
void
*) ((
size_t
) base + offset), sym_value, size);
}
break
;
case
R_GLOB_DAT:
case
R_JUMP_SLOT:
if
(value) {
*(
size_t
*) ((
size_t
) base + offset) = (
size_t
) base + value;
}
else
{
const
void
* sym_value = dlsym((
void
*) -1, name);
// RTLD_DEFAULT
if
(!sym_value) {
LOGW(
"failed to resolve symbol `%s'.\n"
, name);
break
;
}
*(
size_t
*) ((
size_t
) base + offset) = (
size_t
) sym_value;
}
break
;
case
R_RELATIVE:
*(
size_t
*) ((
size_t
) base + offset) = (
size_t
) base + addend;
break
;
case
R_IRELATIVE:
*(
size_t
*) ((
size_t
) base + offset) = ((
size_t
(*)()) ((
size_t
) base + addend))();
break
;
case
1:
// R_X86_64_64
if
(value) {
*(
size_t
*) ((
size_t
) base + offset) = (
size_t
) base + value + addend;
}
else
{
const
void
* sym_value = dlsym((
void
*) -1, name);
// RTLD_DEFAULT
if
(!sym_value) {
LOGW(
"failed to resolve symbol `%s'.\n"
, name);
break
;
}
*(
size_t
*) ((
size_t
) base + offset) = (
size_t
) sym_value + addend;
}
break
;
default
:
LOGW(
"unimplemented reloc type: %d.\n"
, type);
break
;
}
#undef sym
#undef type
#undef value
#undef size
#undef name
return
1;
}
#define SKIP_LOAD_WITH_DL
void
* load_with_dl(
const
char
* path) {
#ifdef SKIP_LOAD_WITH_DL
LOGD(
"SKIP_LOAD_WITH_DL defined, load_with_dl returns NULL.\n"
);
return
NULL;
#endif
LOGI(
"loading %s with dlopen...\n"
, path);
void
* handle = dlopen(path, RTLD_LAZY);
if
(handle == NULL) {
LOGE(
"load_with_dl failed: %s.\n"
, dlerror());
return
NULL;
}
void
* base = *(
void
**) handle;
LOGI(
"done, loaded at %p.\n"
, base);
return
base;
}
int
check_header(elf_header* header) {
if
(*(uint*) header->e_ident != 0x464c457f) {
LOGE(
"elf magic header not detected.\n"
);
return
0;
}
if
(header->e_ident[4] != (
sizeof
(
void
*) / 4)) {
// ei_class, 1: ELFCLASS32, 2: ELFCLASS64
LOGE(
"elf class mismatch.\n"
);
return
0;
}
if
(header->e_ident[5] != 1) {
LOGE(
"LSB expected.\n"
);
return
0;
}
if
(header->e_type != 2 && header->e_type != 3) {
LOGE(
"Dynamic library or executable expected.\n"
);
return
0;
}
if
(header->e_ehsize !=
sizeof
(elf_header)) {
LOGE(
"Unexpected header size.\n"
);
return
0;
}
return
1;
}
const
elf_dyn* find_dyn_entry(
const
elf_dyn* dyn,
int
type) {
for
(; dyn->d_tag != 0; dyn++) {
// DT_NULL
if
(dyn->d_tag == type)
return
dyn;
}
return
NULL;
}
int
do_rel(
void
* base,
const
elf_rel* rel,
int
count,
const
elf_sym* symtab,
const
char
* strtab) {
for
(
int
i = 0; i < count; i++) {
if
(!do_reloc(base, rel[i].r_offset, rel[i].r_info, *(
size_t
*) ((
size_t
) base + rel[i].r_offset), symtab, strtab))
return
0;
}
return
1;
}
int
do_rela(
void
* base,
const
elf_rela* rela,
int
count,
const
elf_sym* symtab,
const
char
* strtab) {
for
(
int
i = 0; i < count; i++) {
if
(!do_reloc(base, rela[i].r_offset, rela[i].r_info, rela[i].r_addend, symtab, strtab))
return
0;
}
return
1;
}
int
check_and_do_rel(
void
* base,
const
elf_dyn* dyn,
const
elf_rel* rel,
const
elf_sym* symtab,
const
char
* strtab) {
if
(find_dyn_entry(dyn, 0x13)->d_un !=
sizeof
(elf_rel)) {
// DT_RELENT
LOGE(
"unexpected rel table entry size.\n"
);
return
0;
}
LOGD(
"do rel.\n"
);
int
rel_count = find_dyn_entry(dyn, 0x12)->d_un /
sizeof
(elf_rel);
// DT_RELSZ
if
(!do_rel(base, rel, rel_count, symtab, strtab))
return
0;
return
1;
}
int
check_and_do_rela(
void
* base,
const
elf_dyn* dyn,
const
elf_rela* rela,
const
elf_sym* symtab,
const
char
* strtab) {
if
(find_dyn_entry(dyn, 0x9)->d_un !=
sizeof
(elf_rela)) {
// DT_RELAENT
LOGE(
"unexpected rela table entry size.\n"
);
return
0;
}
LOGD(
"do rela.\n"
);
int
rela_count = find_dyn_entry(dyn, 0x8)->d_un /
sizeof
(elf_rela);
// DT_RELASZ
if
(!do_rela(base, rela, rela_count, symtab, strtab))
return
0;
return
1;
}
int
load_dynamic(
void
* base,
const
elf_dyn* dyn) {
const
elf_dyn* res = find_dyn_entry(dyn, 5);
// DT_STRTAB
if
(res == NULL) {
LOGE(
"string table not found.\n"
);
return
0;
}
const
char
* strtab = (
const
char
*) ((
size_t
) base + res->d_un);
const
elf_sym* symtab = NULL;
res = find_dyn_entry(dyn, 0x6);
// DT_SYMTAB
if
(res != NULL) {
symtab = (
const
elf_sym*) ((
size_t
) base + res->d_un);
if
(find_dyn_entry(dyn, 0xB)->d_un !=
sizeof
(elf_sym)) {
// DT_SYMENT
LOGE(
"unexpected symbol table entry size.\n"
);
return
0;
}
}
for
(
const
elf_dyn* it = dyn; it->d_tag != 0; it++) {
if
(it->d_tag != 1)
continue
;
// DT_NEEDED: name of needed library
LOGD(
"loading needed library `%s'.\n"
, strtab + it->d_un);
if
(!dlopen(strtab + it->d_un, RTLD_NOW | RTLD_GLOBAL))
LOGW(
"failed to load needed library `%s': %s.\n"
, strtab + it->d_un, dlerror());
}
int
rel_done = 0;
for
(
const
elf_dyn* it = dyn; it->d_tag != 0; it++) {
// DT_NULL
switch
(it->d_tag) {
case
7:
// DT_RELA
if
(rel_done)
break
;
if
(!check_and_do_rela(base, dyn, (
const
elf_rela*) ((
size_t
) base + it->d_un), symtab, strtab))
return
0;
rel_done = 1;
break
;
case
0x11:
// DT_REL
if
(rel_done)
break
;
if
(!check_and_do_rel(base, dyn, (
const
elf_rel*) ((
size_t
) base + it->d_un), symtab, strtab))
return
0;
rel_done = 1;
break
;
case
0x17:
// DT_JMPREL
;
size_t
plt_rel_size = find_dyn_entry(dyn, 0x2)->d_un;
// DT_PLTRELSZ
int
plt_rel = find_dyn_entry(dyn, 0x14)->d_un;
// DT_PLTREL
if
(plt_rel == 0x11) {
// DT_REL
if
(!rel_done) {
res = find_dyn_entry(dyn, 0x11);
// DT_REL
if
(res != NULL) {
if
(!check_and_do_rel(base, dyn, (
const
elf_rel*) ((
size_t
) base + res->d_un), symtab, strtab))
return
0;
rel_done = 1;
}
}
plt_rel_size /=
sizeof
(elf_rel);
LOGD(
"do jmprel with rel.\n"
);
if
(!do_rel(base, (elf_rel*) ((
size_t
) base + it->d_un), plt_rel_size, symtab, strtab))
return
0;
}
else
if
(plt_rel == 7) {
// DT_RELA
if
(!rel_done) {
res = find_dyn_entry(dyn, 7);
// DT_RELA
if
(res != NULL) {
if
(!check_and_do_rela(base, dyn, (
const
elf_rela*) ((
size_t
) base + res->d_un), symtab, strtab))
return
0;
rel_done = 1;
}
}
plt_rel_size /=
sizeof
(elf_rela);
LOGD(
"do jmprel with rela.\n"
);
if
(!do_rela(base, (elf_rela*) ((
size_t
) base + it->d_un), plt_rel_size, symtab, strtab))
return
0;
}
else
{
LOGE(
"unexpected plt rel type: %d.\n"
, plt_rel);
return
0;
}
break
;
}
}
res = find_dyn_entry(dyn, 0xC);
// DT_INIT
if
(res != NULL) {
void
(*init)() = (
void
(*)()) ((
size_t
) base + res->d_un);
LOGI(
"init proc detected: %p.\n"
, init);
int
choice =
'y'
;
do
{
LOGI(
"Execute init proc? [(y)es/(n)o] "
);
choice =
getchar
();
if
(choice !=
'\n'
)
while
(
getchar
() !=
'\n'
) ;
if
(choice >=
'A'
&& choice <=
'Z'
) choice += 0x20;
}
while
(choice !=
'y'
&& choice !=
'n'
);
if
(choice ==
'y'
) init();
}
res = find_dyn_entry(dyn, 0x19);
// DT_INIT_ARRAY
if
(res != NULL) {
void
(**init_array)() = (
void
(**)()) ((
size_t
) base + res->d_un);
int
count = find_dyn_entry(dyn, 0x1B)->d_un /
sizeof
(
size_t
);
// DT_INIT_ARRAYSZ
while
(*init_array == NULL && count) {
init_array++;
count--;
}
if
(count) {
LOGI(
"init array detected:\n"
);
int
choice =
'?'
;
for
(
int
i = 0; i < count; i++) {
if
(!init_array[i])
continue
;
while
(choice !=
'y'
&& choice !=
'n'
&& choice !=
'a'
&& choice !=
'o'
) {
LOGI(
"\texecute function %p? [(y)es/(n)o/(a)ll items left/n(o)ne items left] "
, init_array[i]);
choice =
getchar
();
if
(choice !=
'\n'
)
while
(
getchar
() !=
'\n'
) ;
// skip line
if
(choice >=
'A'
&& choice <=
'Z'
) choice += 0x20;
// convert to lower case
}
if
((uchar) (choice -
'n'
) > 2) {
// 'y' or 'a'
LOGI(
"\texecuting function at %p...\n"
, init_array[i]);
init_array[i]();
if
(choice ==
'y'
) choice =
'?'
;
}
else
if
(choice ==
'n'
) choice =
'?'
;
}
}
}
res = find_dyn_entry(dyn, 0xD);
// DT_FINI
if
(res != NULL) {
void
(*fini)() = (
void
(*)()) ((
size_t
) base + res->d_un);
LOGI(
"fini proc detected: %p.\n"
, fini);
}
res = find_dyn_entry(dyn, 0x1A);
// DT_FINI_ARRAY
if
(res != NULL) {
void
(**fini_array)() = (
void
(**)()) ((
size_t
) base + res->d_un);
int
count = find_dyn_entry(dyn, 0x1C)->d_un /
sizeof
(
size_t
);
// DT_FINI_ARRAYSZ
while
(*fini_array == NULL && count) {
fini_array++;
count--;
}
if
(count) {
LOGI(
"fini array detected:\n"
);
for
(
int
i = 0; i < count; i++) {
if
(fini_array[i]) {
LOGI(
"\t%p\n"
, fini_array[i]);
}
}
}
}
LOGI(
"load_dynamic done.\n"
);
return
1;
}
#define MMAP_LOAD_BASE ((void*) 0xC0000000)
void
* load_with_mmap(
const
char
* path) {
LOGI(
"loading %s with mmap...\n"
, path);
int
fd = open(path, O_RDONLY);
LOGV(
"open(path, O_RDONLY) returns %d\n"
, fd);
elf_header header;
LOGV(
"reading elf header from file...\n"
);
if
(read(fd, &header,
sizeof
(header)) !=
sizeof
(header)) {
LOGE(
"read header error\n"
);
close(fd);
return
NULL;
}
LOGV(
"checking elf header...\n"
);
if
(!check_header(&header)) {
close(fd);
return
NULL;
}
elf_program_header pheader;
elf_dyn* dyn = NULL;
int
e_phentsize = header.e_phentsize;
int
e_phnum = header.e_phnum;
if
(e_phentsize !=
sizeof
(pheader)) {
LOGE(
"unexpected program header size.\n"
);
close(fd);
return
NULL;
}
LOGV(
"determine LOAD_BASE...\n"
);
void
* base = MMAP_LOAD_BASE;
while
(base != mmap(base, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)) {
base = (
void
*) ((
size_t
) base + 0x1000000);
}
munmap(base, 0x1000);
LOGD(
"trying loading at %p\n"
, base);
lseek(fd, header.e_phoff, SEEK_SET);
for
(
int
i = 0; i < e_phnum; i++) {
LOGV(
"processing phdr %d...\n"
, i);
if
(read(fd, &pheader,
sizeof
(pheader)) !=
sizeof
(pheader)) {
LOGE(
"read pheader error\n"
);
close(fd);
return
NULL;
}
if
(pheader.p_type != 1 || pheader.p_memsz == 0) {
// not PT_LOAD or nothing to load
if
(pheader.p_type == 2) {
// DYNAMIC
if
(dyn != NULL) {
LOGE(
"duplicated DYNAMIC PHT detected.\n"
);
close(fd);
return
NULL;
}
else
{
dyn = (elf_dyn*) ((
size_t
) base + pheader.p_vaddr);
}
}
continue
;
}
void
* addr = (
void
*) (((
size_t
) base + pheader.p_vaddr) & ~0xfff);
int
offset = pheader.p_vaddr & 0xfff;
size_t
size = (offset + pheader.p_filesz + 0xfff) & ~0xfff;
if
(addr != mmap(addr, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, pheader.p_offset - offset)) {
// if (addr != mmap(addr, pheader.p_memsz + offset, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, pheader.p_offset - offset)) {
// if ((uchar*) addr != (uchar*) base + pheader.p_vaddr) {
LOGE(
"failed to mmap 0x%lx to 0x%lx.\n"
, pheader.p_offset, pheader.p_vaddr + (
size_t
) base);
close(fd);
return
NULL;
}
if
(offset) {
memset
(addr, 0, offset);
}
if
(pheader.p_memsz != pheader.p_filesz) {
if
(pheader.p_memsz < pheader.p_filesz) {
LOGE(
"unexpected: filesz bigger than memsz.\n"
);
close(fd);
return
NULL;
}
if
(pheader.p_memsz + offset > size) {
LOGV(
"mmap extra pages in memory\n"
);
addr = (
void
*) ((
size_t
) addr + size);
if
(addr != mmap(addr, pheader.p_memsz + offset - size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON | MAP_SHARED, -1, 0)) {
LOGE(
"failed to mmap 0x%lx to 0x%lx.\n"
, pheader.p_offset, pheader.p_vaddr + (
size_t
) base);
close(fd);
return
NULL;
}
}
}
{
LOGV(
"testing memory...\n"
);
char
c = *(unsigned
char
*) (pheader.p_vaddr + (
size_t
) base);
c = *(unsigned
char
*) (pheader.p_vaddr + (
size_t
) base + pheader.p_filesz - 1);
c = *(unsigned
char
*) (pheader.p_vaddr + (
size_t
) base + pheader.p_memsz - 1);
}
LOGD(
"mmaped 0x%lx to 0x%lx, filesz 0x%lx, memsz 0x%lx\n"
, pheader.p_offset, pheader.p_vaddr + (
size_t
) base, pheader.p_filesz, pheader.p_memsz);
}
LOGI(
"done, loaded at %p\n"
, base);
close(fd);
if
(!dyn)
return
base;
LOGI(
"DYNAMIC detected, loading...\n"
);
if
(!load_dynamic(base, dyn))
return
NULL;
return
base;
}
const
elf_dyn* get_dyn(
void
* base) {
elf_header* header = (elf_header*) base;
int
e_phnum = header->e_phnum;
elf_program_header* pheader = (elf_program_header*) ((
size_t
) base + header->e_phoff);
for
(
int
i = 0; i < e_phnum; i++, pheader++) {
if
(pheader->p_type == 2) {
return
(elf_dyn*) ((
size_t
) base + pheader->p_vaddr);
}
}
}
void
* get_symbol_by_name(
void
* base,
const
char
* symbol) {
const
elf_dyn* dyn = get_dyn(base);
const
char
* strtab = (
const
char
*) (find_dyn_entry(dyn, 5)->d_un);
// DT_STRTAB
if
(strtab < (
const
char
*) base)
strtab = (
const
char
*) strtab + (
size_t
) base;
size_t
strsz = find_dyn_entry(dyn, 0xa)->d_un;
// DT_STRSZ
const
elf_sym* symtab = (
const
elf_sym*) (find_dyn_entry(dyn, 6)->d_un);
// DT_SYMTAB
if
((
const
char
*) symtab < (
const
char
*) base)
symtab = (
const
elf_sym*) ((
const
char
*) symtab + (
size_t
) base);
for
(; ; symtab++) {
if
(symtab->st_name == 0)
continue
;
if
(symtab->st_name >= strsz) {
LOGE(
"failed to resolve symbol `%s' from library (%p): not found.\n"
, symbol, base);
return
NULL;
}
if
(
strcmp
(strtab + symtab->st_name, symbol) == 0) {
if
(symtab->st_value == 0) {
LOGE(
"failed to resolve symbol `%s' from library (%p): value is NULL.\n"
, symbol, base);
return
NULL;
}
if
(elf_st_type(symtab->st_info) != 10) {
// STT_GNU_IFUNC
return
(
void
*) ((
size_t
) base + symtab->st_value);
}
return
((
void
* (*)()) ((
size_t
) base + symtab->st_value))();
}
}
}
void
* get_symbol_by_offset(
void
* base,
size_t
offset) {
return
(
void
*) ((
size_t
) base + offset);
}
void
* load_elf(
const
char
* elf_path) {
void
* base = load_with_dl(elf_path);
if
(base == NULL) {
base = load_with_mmap(elf_path);
}
//assert(base != NULL && *(unsigned int*) base == 0x464c457f);
return
base;
}
// gcc ./x64_main.c -o main -g -ldl
__asm__(
"__round:\n"
"sub rsp, 0x10\n"
"mov [rsp+0x8], rdi\n"
"mov r12, rsi\n"
"call rdx\n"
"add rsp, 0x10\n"
"ret\n"
);
void
__round(unsigned
char
* array,
int
key,
void
* entry);
extern
int
bf_round(
int
key,
int
offset,
int
index);
extern
void
setup();
extern
void
one_round(unsigned
char
* array,
int
key,
int
offset);
static
char
* base;
void
setup() {
// SET_LOGE();
const
char
* path =
"./libentry.so"
;
base = load_elf(path);
*(base + 0x2a07) = 0xc3;
// ret
}
void
one_round(unsigned
char
* array,
int
key,
int
offset) {
if
(base == NULL) setup();
__round(array, key, base + offset);
}
unsigned
char
g(unsigned
char
x, unsigned
char
n) {
return
(x >> n) & 1;
}
unsigned
char
s(unsigned
char
x, unsigned
char
n) {
return
(x & 1) << n;
}
unsigned
char
swapbit(unsigned
char
x, unsigned
char
m, unsigned
char
n) {
if
(m == n)
return
x;
return
s(g(x, m), n) | s(g(x, n), m) | (x & ~(s(1, n) | s(1, m)));
}
unsigned
char
bit_length(unsigned
char
x) {
if
(x == 0)
return
0;
for
(
int
i = 8; i > 0; i--) {
if
(x & (1 << (i - 1)))
return
i;
}
}
unsigned
char
swapkeep(unsigned
char
x, unsigned
char
mask) {
unsigned
char
swapbits = ~mask & 0xff;
unsigned
char
m = bit_length(swapbits) - 1;
assert
(0 <= m && m < 7);
swapbits ^= 1 << m;
unsigned
char
n = bit_length(swapbits) - 1;
assert
(0 <= n && n < 7);
swapbits ^= 1 << n;
assert
(swapbits == 0);
return
swapbit(x, m, n);
}
unsigned
char
ror1(unsigned
char
x, unsigned
char
n) {
n &= 7;
x &= 0xff;
return
(x >> n) | (x << (8 - n)) & 0xff;
}
unsigned
char
rol1(unsigned
char
x, unsigned
char
n) {
return
ror1(x, 8 - n);
}
#define XOR 0 // c ^ val0 ^ val1
#define ROT 1 // ror1(c, val0) ^ val1
#define SWP 2 // swapkeep(c, val0) ^ val1
#define MAKE_RET_VAL(type, val0, val1) (((type) << 16) | ((val0) << 8) | (val1))
int
bf_round(
int
key,
int
offset,
int
index) {
if
(base == NULL) setup();
unsigned
char
array[38];
array[index] = 0;
__round(array, key, base + offset);
unsigned
char
val1 = array[index];
int
flag = 0;
// test xor
for
(
int
i = 0; i < 7; i++) {
array[index] = 1 << i;
__round(array, key, base + offset);
array[index] ^= val1;
if
(array[index] != (1 << i)) {
flag = 1;
break
;
}
}
if
(flag == 0) {
// XOR
return
MAKE_RET_VAL(XOR, 0, val1);
}
// test rol1
array[index] = 1;
__round(array, key, base + offset);
array[index] ^= val1;
unsigned
char
val0 = bit_length(array[index]);
assert
(val0 != 0);
val0--;
if
(val0 != 0) {
assert
(array[index] == (1 << val0));
for
(
int
i = 1; i < 7; i++) {
array[index] = 1 << i;
__round(array, key, base + offset);
array[index] ^= val1;
if
(array[index] != (1 << ((i + val0) % 8))) {
flag = 0;
break
;
}
}
if
(flag == 1) {
return
MAKE_RET_VAL(ROT, 8 - val0, val1);
}
}
// swapkeep
for
(
int
i = 0; i < 7; i++) {
array[index] = 1 << i;
__round(array, key, base + offset);
array[index] ^= val1;
if
(array[index] != (1 << i)) {
assert
(bit_length(array[index]));
assert
(array[index] == (1 << (bit_length(array[index]) - 1)));
val0 = ~((1 << i) | array[index]);
return
MAKE_RET_VAL(SWP, val0, val1);
}
}
assert
(0);
}
// gcc ./x64_main.c -o lib -g -ldl -masm=intel -shared
int
main() {
{
const
char
* path =
"/lib/x86_64-linux-gnu/libm.so.6"
;
void
* base = load_elf(path);
double
(*
pow
)(
double
,
double
) = get_symbol_by_name(base,
"pow"
);
double
a = 3.14159;
double
b = a;
printf
(
"%g ** %g == %g\n"
, a, b,
pow
(a, b));
}
/**/
const
char
* path =
"/lib/x86_64-linux-gnu/libc++.so.1"
;
void
* base = load_elf(path);
void
* std_cout = get_symbol_by_name(base,
"_ZNSt3__14coutE"
);
// offset may be different
// std::ostream::operator<<(int)
void
* (*print_int)(
void
*,
int
) = get_symbol_by_offset(base, 0x5e380);
// std::ostream::put(char)
void
* (*print_char)(
void
*,
char
) = get_symbol_by_offset(base, 0x5f510);
print_char(print_int(std_cout, 114514),
'\n'
);
/**/
puts
(
"done."
);
return
0;
}
#include <stdio.h>
#include <dlfcn.h>
#include <string.h>
#include <assert.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdarg.h>
#define ERROR 0
#define WARNING 1
#define INFO 2
#define DEBUG 3
#define VERBOSE 4
const
char
* LOG_LEVEL_CHARS =
"EWIDV"
;
const
char
* LOG_LEVEL_COLORS[] = {
"\x1b[31m"
,
"\x1b[33m"
,
"\x1b[32m"
,
"\x1b[0m"
,
"\x1b[34m"
,
};
int
_log_level = INFO;
int
_log_color = 1;
void
set_log_level(
int
log_level) {
if
(log_level < 0) log_level = 0;
if
(log_level > 4) log_level = 4;
_log_level = log_level;
}
void
set_log_color(
int
log_color) {
_log_color = log_color;
}
void
Log(
int
log_level,
const
char
* format, ...) {
if
(log_level < 0) log_level = 0;
if
(log_level > 4) log_level = 4;
if
(log_level > _log_level)
return
;
if
(_log_color)
printf
(
"%s"
, LOG_LEVEL_COLORS[log_level]);
printf
(
"[%c] "
, LOG_LEVEL_CHARS[log_level]);
va_list
args;
va_start
(args, format);
vprintf
(format, args);
va_end
(args);
if
(_log_color)
printf
(
"\x1b[0m"
);
}
#define LOGE(format, ...) Log(ERROR, format, ##__VA_ARGS__)
#define LOGW(format, ...) Log(WARNING, format, ##__VA_ARGS__)
#define LOGI(format, ...) Log(INFO, format, ##__VA_ARGS__)
#define LOGD(format, ...) Log(DEBUG, format, ##__VA_ARGS__)
#define LOGV(format, ...) Log(VERBOSE, format, ##__VA_ARGS__)
// default info
#define SET_LOGE() set_log_level(ERROR)
#define SET_LOGW() set_log_level(WARNING)
#define SET_LOGI() set_log_level(INFO)
#define SET_LOGD() set_log_level(DEBUG)
#define SET_LOGV() set_log_level(VERBOSE)
// default on
#define SET_LOGCOLOR_OFF() set_log_color(0)
#define SET_LOGCOLOR_ON() set_log_color(1)
#define R_NONE 0
#define R_COPY 5
#define R_GLOB_DAT 6
#define R_JUMP_SLOT 7
#define R_RELATIVE 8
#define R_IRELATIVE 37
typedef
unsigned
char
uchar;
typedef
unsigned
short
ushort;
typedef
unsigned
int
uint;
typedef
unsigned
long
long
ullong;
typedef
struct
{
uchar e_ident[16];
ushort e_type;
ushort e_machine;
uint e_version;
size_t
e_entry;
size_t
e_phoff;
size_t
e_shoff;
uint e_flags;
ushort e_ehsize;
ushort e_phentsize;
ushort e_phnum;
ushort e_shentsize;
ushort e_shnum;
ushort e_shtrndx;
} elf_header;
typedef
struct
{
size_t
d_tag;
size_t
d_un;
} elf_dyn;
typedef
struct
{
size_t
r_offset;
size_t
r_info;
} elf_rel;
typedef
struct
{
size_t
r_offset;
size_t
r_info;
size_t
r_addend;
} elf_rela;
// elf_sym.st_info
#define elf_st_bind(info) ((info) >> 4)
#define elf_st_type(info) ((info) & 0xf)
typedef
struct
{
uint p_type;
uint p_flags;
size_t
p_offset;
size_t
p_vaddr;
size_t
p_paddr;
size_t
p_filesz;
size_t
p_memsz;
size_t
p_align;
} elf_program_header;
typedef
struct
{
uint st_name;
uchar st_info;
uchar st_other;
ushort shndx;
size_t
st_value;
size_t
st_size;
} elf_sym;
// elf_rel[a].r_info
#define elf_r_sym(info) ((info) >> 32)
#define elf_r_type(info) ((uint) (info))
int
do_reloc(
void
* base,
size_t
offset,
size_t
info,
size_t
addend,
const
elf_sym* symtab,
const
char
* strtab) {
#define sym (elf_r_sym(info))
#define type (elf_r_type(info))
#define value (symtab[sym].st_value)
#define size (symtab[sym].st_size)
#define name (strtab + symtab[sym].st_name)
switch
(type) {
case
R_NONE:
break
;
case
R_COPY:
if
(value) {
memcpy
((
void
*) ((
size_t
) base + offset), (
const
void
*) ((
size_t
) base + value), size);
}
else
{
const
void
* sym_value = dlsym((
void
*) -1, name);
// RTLD_DEFAULT
if
(!sym_value) {
LOGW(
"failed to resolve symbol `%s'.\n"
, name);
break
;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
赞赏
|
|
---|---|
|
楼主,最后的ida小技巧是不是忘记编写了呢
|
|
mb_ldbucrik 楼主,最后的ida小技巧是不是忘记编写了呢忘记说明了:点击Collapse declarations可以把IDA超长的变量声明缩减成一行! |
|
学到了
|
|
Loserme 忘记说明了:点击Collapse declarations可以把IDA超长的变量声明缩减成一行!按个减号就行了。。 |