iOS Swift逆向——被编译优化后的函数参数调用约定修复

头文件导入:

cpp 复制代码
typedef long long s64;
typedef unsigned long long u64;

typedef s64 Int;
typedef u64 Bool;

struct Swift::String
{
  u64 _countAndFlagsBits;
  void *_object;
};

union Swift_ElementAny {
    Swift::String stringElement;
};

struct Swift_Any {
    Swift_ElementAny element;
    u64 unknown;
    s64 type;
};

struct Swift_ArrayAny {
    s64 length;
    Swift_Any *items;
};

https://github.com/doronz88/swift_reversing

https://github.com/doronz88/ida-scripts/blob/main/swift.py

Swift <=> OC的兼容层

小gadget(片段)

cpp 复制代码
; void sub_101A34B60()
sub_101A34B60
MOV             X0, X20 ; id
B               _objc_release
; End of function sub_101A34B60

因为_objc_release的参数只要X0。修复为:

cpp 复制代码
void __usercall sub_101A34B60(__int64 a1@<X20>)

根据swift官方文档,X20是self。所以这是内存引用计数-1。

https://github.com/swiftlang/swift/blob/13da4c2ad3077282f7c8922b293a74c32e79e428/docs/ABI/CallConvSummary.rst#L151


字符串操作

字符串对象由两个寄存器构成。

以String.append为例进行修复调用约定:

X20是self。

cpp 复制代码
Swift::Void __usercall String.append(_:)(void *a1@<X20>, Swift::String a2@<X0:X1>)
{
  __imp__$sSS6appendyySSF(a2._object, a2._countAndFlagsBits);
}
cpp 复制代码
Swift::String __usercall dispatch thunk of CustomStringConvertible.description.getter@<X0:X1>(
        void *a1@<X20>,
        __int64 *a2@<X0>,
        __int64 *a3@<X1>)

a=100;print("myIntVariable1= \(a)")的整理后IDA结果:

cpp 复制代码
  v11 = 0xD000000000000010LL;                   // myIntVariable1= 
  v12 = (id)0x800000010000CDF0LL;
  v10 = 100LL;
  v3 = dispatch thunk of CustomStringConvertible.description.getter(
         &v10,
         &type metadata for Int,
         &protocol witness table for Int);
  String.append(_:)(&v11, (Swift::String)__PAIR128__(v3._countAndFlagsBits, (unsigned __int64)v3._object));
  swift_bridgeObjectRelease(v3._object);
  v4 = v11;
  v5 = v12;
  *(_QWORD *)(v2 + 56) = &type metadata for String;
  *(_QWORD *)(v2 + 32) = v4;
  *(_QWORD *)(v2 + 40) = v5;
  v15._countAndFlagsBits = 32LL;
  v15._object = (void *)0xE100000000000000LL;
  v18._countAndFlagsBits = 10LL;
  v18._object = (void *)0xE100000000000000LL;
  print(_:separator:terminator:)((Swift_ArrayAny *)v2, v15, v18);
  swift_release(v2);

字符串Array

Swift::String __usercall BidirectionalCollection___joined_separator__@<X0:X1>(Swift_ArrayAny@<X20:X21>, Swift::String@<X0:X1>, __int64@<X2>, __int64@<X3>)

栈内存偏移计算相关小函数

原先的函数点开里面是空的。

cpp 复制代码
sub_101A348B8
LDUR            X8, [X0,#-8]
LDR             X8, [X8,#0x40]
MOV             X9, SP
ADD             X8, X8, #0xF
AND             X8, X8, #0xFFFFFFFFFFFFFFF0
SUB             X19, X9, X8
MOV             SP, X19
RET
; End of function sub_101A348B8

定义结构体:

cpp 复制代码
00000000 stack_offset_struc struc ; (sizeof=0x18, copyof_7619)
00000000 offset          DCQ ?
00000008 sp              DCQ ?
00000010 addr            DCQ ?
00000018 stack_offset_struc ends

定义调用约定。F5之后,函数体原来出现内容。

cpp 复制代码
stack_offset_struc __usercall __spoils<> sub_101A348B8@<0:X8, 8:X9, 16:X19>(__int64 a1@<X0>)
{
  __int64 *v1; // x9
  __int64 v2; // x8
  char *v3; // x19
  __int64 v4; // [xsp+0h] [xbp+0h] BYREF
  stack_offset_struc result; // 0:x8.16,16:x19.8

  v1 = &v4;
  v2 = (*(_QWORD *)(*(_QWORD *)(a1 - 8) + 64LL) + 15LL) & 0xFFFFFFFFFFFFFFF0LL;
  v3 = (char *)&v4 - v2;
  result.addr = (__int64)v3;
  result.sp = (__int64)v1;
  result.offset = v2;
  return result;
}

另一个函数也进行修复:

cpp 复制代码
sub_101A34B84
LDUR            X28, [X0,#-8]
LDR             X8, [X28,#0x40]
MOV             X9, SP
ADD             X8, X8, #0xF
AND             X8, X8, #0xFFFFFFFFFFFFFFF0
RET
cpp 复制代码
stack_offset_struc __usercall __spoils<> sub_101A34B84@<0:X8, 8:X9, 16:X28>(__int64 a1@<X0>)
{
  __int64 v1; // x28
  __int64 *v2; // x9
  __int64 v3; // x8
  __int64 v4; // [xsp+0h] [xbp+0h] BYREF
  stack_offset_struc result; // 0:x8.16,16:x28.8

  v1 = *(_QWORD *)(a1 - 8);
  v2 = &v4;
  v3 = (*(_QWORD *)(v1 + 64) + 15LL) & 0xFFFFFFFFFFFFFFF0LL;
  result.addr = v1;
  result.sp = (__int64)v2;
  result.offset = v3;
  return result;
}

这两个小函数,其实是完全一样的。

可以发现第二个函数sub_101A34B84相比较于sub_101A348B8少了最后的SUB。其实这个SUB在上层调用者函数里面,看最后两行汇编:

cpp 复制代码
STP             X28, X27, [SP,#-0x10+var_50]!
STP             X26, X25, [SP,#0x50+var_40]
STP             X24, X23, [SP,#0x50+var_30]
STP             X22, X21, [SP,#0x50+var_20]
STP             X20, X19, [SP,#0x50+var_10]
STP             X29, X30, [SP,#0x50+var_s0]
ADD             X29, SP, #0x50
SUB             SP, SP, #0x70
MOV             X20, X3
MOV             X23, X2
MOV             X24, X1
MOV             X25, X0
ADRL            X21, unk_1039839C0
MOV             X0, X21
BL              sub_1000B6ED0
BL              sub_101A348B8
BL              sub_101A34D54
MOV             X22, X0
BL              sub_101A34B84
SUB             X27, X9, X8
MOV             SP, X27

修复完成后,返回调用该函数的上层函数,在按F5。可以看到恢复之后的代码。

参考IDA官网博客里面的内容:

https://hex-rays.com/blog/author/igor-skochinsky

相关推荐
禁默7 分钟前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Code哈哈笑17 分钟前
【Java 学习】深度剖析Java多态:从向上转型到向下转型,解锁动态绑定的奥秘,让代码更优雅灵活
java·开发语言·学习
程序猿进阶20 分钟前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
qq_4336184422 分钟前
shell 编程(二)
开发语言·bash·shell
charlie11451419137 分钟前
C++ STL CookBook
开发语言·c++·stl·c++20
袁袁袁袁满37 分钟前
100天精通Python(爬虫篇)——第113天:‌爬虫基础模块之urllib详细教程大全
开发语言·爬虫·python·网络爬虫·爬虫实战·urllib·urllib模块教程
ELI_He99943 分钟前
PHP中替换某个包或某个类
开发语言·php
m0_748236111 小时前
Calcite Web 项目常见问题解决方案
开发语言·前端·rust
东坡肘子1 小时前
肘子的 Swift 周报 #063|异种肾脏移植取得突破
swiftui·swift·apple
倔强的石头1061 小时前
【C++指南】类和对象(九):内部类
开发语言·c++