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狗

相关文章
|
5月前
|
小程序 视频直播 数据安全/隐私保护
如何在1v1视频直播交友APP中实现防录屏防截屏功能?
婚恋交友市场快速增长,1v1社交应用海外投放增86.49%,中东、东南亚及北美需求旺盛。用户偏好私密高效交流,国内“云相亲”兴起。开发需合规备案、实名认证,并防范诈骗。本文详解原生APP防录屏技术:Android通过MediaProjection检测,iOS监听UIScreen状态,结合动态水印、远程销毁等增强防护,平衡体验与安全。
|
6月前
|
JSON 监控 数据格式
1688 item_search_app 关键字搜索商品接口深度分析及 Python 实现
1688开放平台item_search_app接口专为移动端优化,支持关键词搜索、多维度筛选与排序,可获取商品详情及供应商信息,适用于货源采集、价格监控与竞品分析,助力采购决策。
|
6月前
|
缓存 监控 Android开发
京东 item_get_app 接口深度分析及 Python 实现
京东item_get_app接口可获取商品原始详情数据,包含更丰富的字段和细节,适用于电商分析、价格追踪等场景。需通过认证获取权限,支持字段筛选和区域化数据查询。
|
7月前
|
缓存 数据挖掘 API
淘宝 item_get_app 接口深度分析及 Python 实现
淘宝item_get_app接口是淘宝开放平台提供的移动端商品详情数据获取接口,相较PC端更贴近APP展示效果,支持获取APP专属价格、促销活动及详情页结构,适用于电商导购、比价工具、数据分析等场景。接口采用appkey+appsecret+session认证机制,需申请相应权限。本文提供Python调用示例及使用注意事项,帮助开发者高效对接移动端商品数据。
|
9月前
|
JavaScript
TypeOrmModule 从 app.module.ts 抽离到 database.module.ts 后出现错误的原因分析
本文分析了TypeORM实体元数据错误的成因,主要涉及实体注册方式、路径解析差异及模块结构变化导致的关系解析问题,并提供了具体解决方案和最佳实践建议。
210 56
|
6月前
|
缓存 供应链 开发者
1688 item_get_app 接口深度分析及 Python 实现
1688平台item_get_app接口专为移动端设计,提供商品原始详情数据,包含批发价格、起订量、供应商信息等B2B特有字段,适用于采购决策、供应链分析等场景。接口需通过appkey+access_token认证,并支持字段筛选,返回结构化数据,助力企业实现智能采购与供应商评估。
|
7月前
|
数据采集 数据可视化 API
驱动业务决策:基于Python的App用户行为分析与可视化方案
驱动业务决策:基于Python的App用户行为分析与可视化方案
【Azure 应用服务】App Service频繁出现 Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener 异常分析
【Azure 应用服务】App Service频繁出现 Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener 异常分析
232 2
|
11月前
|
数据采集 数据可视化 数据挖掘
基于Python的App流量大数据分析与可视化方案
基于Python的App流量大数据分析与可视化方案
|
开发框架 监控 .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
349 5