App逆向百例|16|某交友App花指令分析

简介: App逆向百例|16|某交友App花指令分析

观前提示:

本文章仅供学习交流,切勿用于非法通途,如有侵犯贵司请及时联系删除

样本:aHR0cHM6Ly9wYW4uYmFpZHUuY29tL3MvMTRWbXVfeHlDN2lGYk9qYjBtOHpYc3c/cHdkPWxpbm4=

0x1 花指令分析

大姐姐打开libsoulpower.so

直接跳转到0xaa73c

如果发现这里没被正常识别

直接在0xaa73c处快捷键P即可

直接F5反编译看伪代码

然后就会发现不明代码

转到汇编

这里是将R0的值作为地址 跳转到该地址处

BX              R0

那么R0从哪里来呢 继续往上看

这里调用了sub_AECF0并且将返回值放在了R0

BL              sub_AECF0

所以真实的跳转地址可能就是在sub_AECF0中计算得出的

继续往上看还能看到入参的操作

LDR             R0, =(off_2C1B64 - 0xAA7A4)
MOV             R1, #0
STR             R1, [SP,#160]
MOV             R1, #1
ADD             R0, PC, R0 ; off_2C1B64

这里IDA已经帮我们识别好了伪代码 直接看就行

sub_AECF0(&off_2C1B64, 1)

sub_AECF0看是啥操作

int __fastcall sub_AECF0(int a1, int a2)
{
  return *(_DWORD *)(a1 + 4 * a2);
}

很简单啊 直接复现一下

0x2C1B64 + 4 * 1 = 0x2C1B68

得到0x2C1B68后 跳转过去

002C1B68                 DCD sub_AA7B8

可以看到0x2C1B68对应的就是sub_AA7B8

所以 R0 = 0xAA7B8

而IDA并不会去执行这些操作 所以达到花指令的目标

0x2 手动去花

前面计算了R0的真实跳转地址

拿到真实地址后就可以在0xAA7B4处手动Patch下图0xAA7B4给错正确0xAA7B8

Patch完事之后再次F5反编译

反编译完发现代码仅仅多了一行

转到汇编 这里同样出现BX R0

所以这个样本应该是多处插花 那就继续还原

按上述操作 找到俩个传入参数 然后手动计算出真实地址

0x2C1B64 + 4 * 2 = 0x2C1B6C

002C1B6C                 DCD sub_AA9F8

R0 = 0xAA9F8

继续重复操作Patch

代码又多了一点 然后不出意料 又是一处插花

LDR             R0, =(off_2C1B64 - 0xAAA08)
MOV             R1, #3
ADD             R0, PC, R0 ; off_2C1B64
BL              sub_AECF0
BX              R0

继续重复几次操作后 代码多了这么多 但是还没完全去花

同时在视图中可以发现ollvm 后面还不知道会出现啥 继续Patch

停!!!

怎么可能 量很大 年轻人 你把握不住的 该上脚本了!

0x3 脚本去花

首先明确要干啥先

  1. 找出所有的插花方法
  2. 找出所有插花方法的调用处
  3. 拿到俩个参数
  4. 计算正确地址
  5. Patch

前面我们知道 每次计算都会进入sub_AECF0

但是我猜测可能不止一个sub_AECF0

也许是同操作 但是方法名不一样 这里做个验证

拿到方法HEX01 01 90 E7 1E FF 2F E1

01 01 90 E7                 LDR             R0, [R0,R1,LSL#2]
1E FF 2F E1                 BX              LR

然后Binary search

搜索得出五个结果

查看每个方法的交叉引用都有很多处

那可以使用idautils.CodeRefsTo遍历交叉引用

但是我担心有可能存在漏识别 所以我采用了从头到尾的遍历方法

import capstone
from keystone import *
import flare_emu
import ida_ida
import idautils
import idaapi
import ida_segment
import idc
import ida_bytes
# 初始化架构和模式
CS = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_ARM)
# 设置为详细反汇编模式
CS.detail = True
# 设置反汇编跳过数据
CS.skipdata = True
# 获取.text段的范围
def getAddrRange():
    start = ida_ida.inf_get_min_ea()
    size = ida_ida.inf_get_max_ea() - start
    # 将地址范围限定于text节
    for seg in idautils.Segments():
        seg = idaapi.getseg(seg)
        segName = ida_segment.get_segm_name(seg)
        if segName == ".text":
            start = seg.start_ea
            size = seg.size()
    return start, size
def binSearch(start, end, pattern):
    matches = []
    addr = start
    if end == 0:
        end = idc.BADADDR
    if end != idc.BADADDR:
        end = end + 1
    while True:
        addr = ida_bytes.bin_search(addr, end, bytes.fromhex(pattern), None, idaapi.BIN_SEARCH_FORWARD,
                                    idaapi.BIN_SEARCH_NOCASE)
        if addr == idc.BADADDR:
            break
        else:
            matches.append(addr)
            addr = addr + 1
    return matches
# 获取代码段的起始地址和长度
start, size = getAddrRange()
codebytes = idc.get_bytes(start, size)
sub_matches = binSearch(0, 0, "01 01 90 E7 1E FF 2F E1")
disasmCodes = list(CS.disasm_lite(codebytes, start, size))
for i in range(len(disasmCodes)):
    (address, size, mnemonic, op_str) = disasmCodes[i]
    if mnemonic == 'bl':
        sub_addr = int(op_str.replace('#', ''), 16)
        if sub_addr in sub_matches:
            print(hex(address))

效果很不错 找出了很多的调用处

找出调用处随便跳转几个看能不能找到规律匹配参数

这里发现 参数的位置并不固定 不好做匹配

但是又可以发现 参数位置 调用位置 跳转位置 都是处于同一个block中

知道了这一点 就只需要匹配出相对应的block就可以了

def find_block(blocks, addr):
    for block in blocks:
        start_ea = block.start_ea
        end_ea = block.end_ea
        if start_ea < addr < end_ea:
            return block
    return None
func = idaapi.get_func(address)
  if func:
    block = find_block(idaapi.FlowChart(func), address)

即使匹配出了地址块 也不好匹配出参数 那咋办呢

其实 这里我匹配地址块的原因就是不想再写一堆匹配代码找出R0R1

所以我打算交给unicorn去做

而我又懒得写很多代码 所以 我又使用了封装好的flare_emu

例如 我匹配出了一个block 我仅需要把block的起始地址匹配到方法执行前即可

测试看结果

import flare_emu
myEH = flare_emu.EmuHelper()
myEH.emulateRange(
  startAddr=0x804DC,
  endAddr=0x804FC
)
Out[31]: <unicorn.unicorn.Uc at 0x169c478b908>
myEH.getRegVal("R0")
Out[32]: 0x2c14d0 (OCSP_SIGNATURE_it + 0x2dc)
myEH.getRegVal("R1")
Out[33]: 1

效果完美

后面仅需自己写个计算方法 将参数传入计算即可

def calcu_addr(a, b):
    return a + 4 * b

得到真实跳转地址后 还得匹配出跳转地址存储的地址

idc.print_operand 刚好能实现这个操作

idc.print_operand(0x2c14d4,0)
Out[34]: 'sub_80508'

拿到这个真实地址 最后Patch就行

不过这里需要注意的是 我们不知道后面第几行是需要Patch的BX

但是我们前面就得到了块的起始地址 同样的也可以得到块的结束地址

只需要(结束地址-方法调用地址)/4 然后遍历就能找到BX所在位置

但是但是 我觉得不优雅

从这张图 可以知道BX一直在块的最后一行 那我何必去遍历呢 直接那最后一行的地址不就行了

一下子就优雅起来了

最后写下patch

code = f"B {hex(b_addr)}"
b_code = generate(code, block.end_ea - 4)
# Patch 1 处理花指令
ida_bytes.patch_bytes(block.end_ea - 4, bytes(b_code))

将所有代码串起来 执行测试一下效果

执行完后应用更改

最后重新打开so

跳转到最开始分析的0xaa73c

成功识别到N多行代码了

去花工作完成 处理脚本和对应的so文件放在样本中



如果你想学习关于so反混淆相关的知识

例如IDA脚本开发 字符串加密处理 花指令处理 龙龙的星球里都写得很详细

龙龙老卷王了 内容丰富  很多东西我都是跟着龙龙学的 让我受益匪浅

所以 我吹爆! 



感谢各位大佬观看

感谢大佬们的文章分享 

如有错误 还请海涵

共同进步 带带弟弟


点赞 在看 分享是你对我最大的支持

逆向lin狗

相关文章
|
4月前
【Azure 应用服务】App Service频繁出现 Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener 异常分析
【Azure 应用服务】App Service频繁出现 Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener 异常分析
|
1月前
|
开发框架 监控 .NET
【Azure App Service】部署在App Service上的.NET应用内存消耗不能超过2GB的情况分析
x64 dotnet runtime is not installed on the app service by default. Since we had the app service running in x64, it was proxying the request to a 32 bit dotnet process which was throwing an OutOfMemoryException with requests >100MB. It worked on the IaaS servers because we had the x64 runtime install
|
3月前
|
安全
【Azure App Service】App service无法使用的情况分析
App Service集成子网后,如果子网网段中的剩余IP地址非常少的情况下,会在App Service实例升级时( 先加入新实例,然后在移除老实例 )。新加入的实例不能被分配到正确的内网IP地址,无法成功的访问内网资源。 解决方法就是为App Service增加子网地址, 最少需要/26 子网网段地址。
|
4月前
【Azure Function App】本地运行的Function发布到Azure上无法运行的错误分析
【Azure Function App】本地运行的Function发布到Azure上无法运行的错误分析
|
4月前
|
JSON 数据格式
【Azure 应用服务】Azure Function App 执行PowerShell指令[Get-Azsubscription -TenantId cxt]错误
【Azure 应用服务】Azure Function App 执行PowerShell指令[Get-Azsubscription -TenantId cxt]错误
【Azure 应用服务】Azure Function App 执行PowerShell指令[Get-Azsubscription -TenantId  cxt]错误
|
4月前
|
开发框架 缓存 .NET
【App Service】在Azure App Service中分析.NET应用程序的性能的好帮手(Review Stack Traces)
【App Service】在Azure App Service中分析.NET应用程序的性能的好帮手(Review Stack Traces)
|
4月前
|
C# 开发工具
【Azure 应用服务】Azure Function App使用SendGrid发送邮件遇见异常消息The operation was canceled,分析源码渐入最源端
【Azure 应用服务】Azure Function App使用SendGrid发送邮件遇见异常消息The operation was canceled,分析源码渐入最源端
|
4月前
|
网络协议 NoSQL 网络安全
【Azure 应用服务】由Web App“无法连接数据库”而逐步分析到解析内网地址的办法(SQL和Redis开启private endpoint,只能通过内网访问,无法从公网访问的情况下)
【Azure 应用服务】由Web App“无法连接数据库”而逐步分析到解析内网地址的办法(SQL和Redis开启private endpoint,只能通过内网访问,无法从公网访问的情况下)
|
5月前
|
存储 前端开发 测试技术
同城交友APP系统开发运营版/案例详细/功能步骤/逻辑方案
开发一款同城交友APP系统需要经过以下大致流程:
|
6月前
|
移动开发 小程序 开发工具
微信支付的类型分析(JSAPI+APP+H5+NATIVE+付款码+合单)
微信支付的类型分析(JSAPI+APP+H5+NATIVE+付款码+合单)
615 1

热门文章

最新文章

下一篇
DataWorks