首页
社区
课程
招聘
[原创]京麒CTF2024-HarmonyOS移动端Native层逆向
发表于: 2024-6-5 06:47 24661

[原创]京麒CTF2024-HarmonyOS移动端Native层逆向

2024-6-5 06:47
24661

鸿蒙HarmonyOS逆向

找到的工具: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期)

最后于 2024-6-5 13:48 被Brinmon编辑 ,原因:
上传的附件:
收藏
免费 3
支持
分享
最新回复 (4)
雪    币: 10
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
楼主,最后的ida小技巧是不是忘记编写了呢
2024-6-5 09:52
0
雪    币: 1968
活跃值: (1573)
能力值: ( LV12,RANK:200 )
在线值:
发帖
回帖
粉丝
3
mb_ldbucrik 楼主,最后的ida小技巧是不是忘记编写了呢
忘记说明了:点击Collapse declarations可以把IDA超长的变量声明缩减成一行!
2024-6-5 11:23
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
学到了
2024-7-8 14:39
0
雪    币: 34
活跃值: (734)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
Loserme 忘记说明了:点击Collapse declarations可以把IDA超长的变量声明缩减成一行!
按个减号就行了。。
2024-9-2 09:33
0
游客
登录 | 注册 方可回帖
返回
//