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

相关推荐
rkmhr_sef25 分钟前
QoS质量配置
开发语言·智能路由器·php
wclass-zhengge1 小时前
02C#基本结构篇(D1_基本语法)
开发语言·microsoft·c#
hrrrrb1 小时前
【C语言】数组篇
c语言·开发语言
蜡笔小新..3 小时前
R语言和RStudio安装
开发语言·r语言
ALPH_3 小时前
R语言的基础命令及实例操作
开发语言·数据分析·r语言·perl·r语言-4.2.1
咩咩觉主3 小时前
C# &Unity 唐老狮 No.6 模拟面试题
开发语言·unity·面试·c#·游戏引擎·唐老师
*.✧屠苏隐遥(ノ◕ヮ◕)ノ*.✧6 小时前
C语言_数据结构总结8:链式队列
c语言·开发语言·数据结构·链表·visualstudio·visual studio
千里码aicood6 小时前
[含文档+PPT+源码等]精品基于Python实现的校园小助手小程序的设计与实现
开发语言·前端·python
讨厌下雨的天空6 小时前
C++之list
开发语言·c++·list
大麦大麦6 小时前
深入剖析 Sass:从基础到进阶的 CSS 预处理器应用指南
开发语言·前端·css·面试·rust·uni-app·sass