将汇编代码还原成高级代码
使用工具ida 或 hopper,我这里使用的是ida
,ida
有64位和32位两个版本,这里使用64位
将编译包拖到ida中,按住control
+滚动鼠标可控制窗口大小
funcAdd
函数
一步一步粗略转换成OC语言
int var4 = wo;
int var8 = w1;
printf("test") // 获取常量test
int global = x30; // 全能局变量
int w1 = var4;
int w8 = var8;
int w8 = w1 + w8;
int w1 = x30;
int w8 = w8 + w1;
int varc = wo;
return x8
自下而上逐渐精简最后变为
printf("test") // 获取常量test
return var4 + var8 + global;
可见这个funcAdd
函数是一个含有两个基础类型变量返回值也为基础类型的一个函数
还原高级代码的过程,通常并不知道参数类型,这要参照上下文及使用到的寄存器来粗略判断
还原后要判断还原的是否正确可以将还原后的包拖到ida
中,查看汇编代码和还原前的是否的一致
常用标识指令
CMP 把一个寄存器的内容和另一个寄存器的内容或立即数进行比较。但不存储结果,只是正确的更改标志。一般CMP做完判断后会进行跳转,后面通常会跟上B指令
- BL 标号:跳转到标号处执行
- B.GT 标号:比较结果是大于(greater than),执行标号,否则不跳转
- B.GE 标号:比较结果是大于等于(greater than or equal to),执行标号,否则不跳转
- B.EQ 标号:比较结果是等于,执行标号,否则不跳转
- B.HI 标号:比较结果是无符号大于,执行标号,否则不跳转
if语句
int global = 16;
void function(int a, int b) {
if (a > global) {
global = a;
} else {
global = b;
}
}
int main(int argc, char * argv[]) {
function(10, 20);
}
循环
do while
循环
int sum = 0;
int i = 0;
do {
sum += i;
} while (i < 100);
while
循环
int sum = 0;
int i = 0;
while (i < 100) {
sum += i;
}
for
循环
for (int i = 0; i < 100; i++) {
printf("hello world");
}
switch
循环
- 在switch语句的分支比较少的时候(少于4的时候没有意义)没有必要使用此结构,相当于if
- 各个分支常量的差值较大的时候,编译器会在效率还是内存进行取舍,这个时候编译器还是会编译成类似于if,else的结构
- 在分支比较多的时候:在编译的时候会生成一个表(跳转表每个地址四个字节)
1 | void func (int a) { |
void func (int a) {
switch (a) {
case 1:
printf("this is one");
break;
case 2:
printf("this is two");
break;
case 3:
printf("this is three");
break;
case 4:
printf("this is four");
break;
case 5:
printf("this is five");
break;
default:
printf("this is else");
break;
}
}
int main(int argc, char * argv[]) {
func(6);
}
编译器优化
上面看到的这些汇编代码,都是在DEBUG
调试状态下的代码,可以发现会有很多冗余代码,寄存器和内存的各种读取等,其实在RELEASE
模式下🍎对我们的汇编代码做了一层优化,如果想在DEBUG
模式下也做一层优化需要额外设置
测试代码
int main(int argc, char * argv[]) {
int a = 10;
int b = 20;
int c = a + b;
NSLog(@"%d",c);
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
优化前
优化后
寄存器与多线程
注意,寄存器的读写其实是线程不安全的,但是,我们的操作系统在切换线程的时候,对当前线程在使用的寄存器进行了一层保护,操作系统内部有一个结构体,记录在使用的寄存器状态,当再次线程切换回来的时候会去获取使用到的寄存器的值。而这一切操作系统已经帮我们搞定了,不需要人为干预
指针相关
编译器决定了指针不能做乘法和除法。指针加减的结果,其实就是由针指向的数据类型宽度决定的,它的运算单位是数据类型的宽度
int main(int argc, char * argv[]) {
int *a;
int b = 6;
a = &b;
}
}
int main(int argc, char * argv[]) {
char *a;
char b = *a;
return 1;
}
如有任何疑问或问题请联系我:fishnewsdream@gmail.com,欢迎交流,共同提高!
Objective-C/Swift技术开发交流群201556264,讨论何种技术并不受限,欢迎各位大牛百家争鸣!
微信公众号OldDriverWeekly
,欢迎关注并提出宝贵意见
老司机iOS周报,欢迎关注或订阅
刚刚在线工作室,欢迎关注或提出建设性意见!
刚刚在线论坛, 欢迎踊跃提问或解答!
如有转载,请注明出处,谢谢!