Hopper Disassembler 反编译之导出伪代码


目的:使用Hopper Disassembler, 通过将汇编代码转成伪代码,了解其他App的实现, 以学习他人优秀的精髓之处;

已上传网盘: Hopper+4.0.8 网盘密码:zr4t Hopper Disassembler v3 网盘密码:hvxs

使用Hopper Disassembler

  • 下载完成打开它 屏幕快照 2018-01-17 上午12.25.29.png

  • 反编译示例: 光标移动到要反编译的汇编代码处: Snip20180117_3.png

查看伪代码:点击Hopper Disassembler的菜单-Window –Show Pseudo Code Of Procedure: 屏幕快照 2018-01-17 上午12.35.08.png

使用Python 脚本导出伪代码

只对Hopper Disassembler v3有效 下面转载: Hopper Disassembler批量导出反编译的伪代码 他的GitHub https://github.com/poboke/Class-Decompile 使用方法:

  1. 将下载的Class Decompile.py文件放到~/Library/Application Support/Hopper/Scripts目录里。
  2. 将可执行文件拖到Hopper里,等待分析完成。如果日志框里出现以下文字,就说明分析完成了: ``` Analysis segment __LINKEDIT Analysis segment External Symbols Background analysis ended
3. 点击菜单 Scripts –> Class Decompile :
![Snip20180117_4.png](http://upload-images.jianshu.io/upload_images/2135374-ce07fe23951a732d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

4. Hopper会出现一个弹框,可以选择反编译类型:
![屏幕快照 2018-01-17 上午12.41.11.png](http://upload-images.jianshu.io/upload_images/2135374-41f48866942f00b4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  • Decompile All Classes : 反编译所有类
  • Decompile One Class : 反编译单个类
  • Cancel : 取消 ```
  • 如果选择反编译单个类的话,会出现以下弹框: Snip20180117_6.png 输入某个类名后,点击 OK 按钮就可以反编译出该类的伪代码。

  • 反编译出来的伪代码保存在~/ClassDecompiles目录里。

  • 打开反编译的文件,例如CalculatorController.m,可以看到生成的伪代码: ``` @implementation TTFQuizShowLiveRoomViewModel

  • (id)init { sp = sp - 0x8; var_0 = self; arg_4 = *0x2352ee8; r4 = loc_e09fa0(sp, @selector(init), 0x2330704); if (r4 != 0x0) {

    loc_e09f98(r4, @selector(setActivityStatus:), 0x0);
          loc_e09f98(r4, @selector(setCurUsersCount:), 0x0, 0x0);
          loc_e09f98(r4, @selector(setCurSignCount:), 0x0, 0x0);
          loc_e09f98(r4, @selector(setNetFailedQuestionID:), 0xffffffff);
          loc_e09f98(r4, @selector(setIsLiveRoomIndexSuccess:), 0x0);
          loc_e09f98(r4, @selector(setIsLiveRoomInitSuccess:), 0x0);
          loc_e09f98(r4, @selector(setKickoutNetError:), 0x0);
          loc_e09f98(r4, @selector(setSubmitRetryCount:), 0x0);
          loc_e09f98(r4, @selector(setSubmitRetryTimeout:), 0x4);
          loc_e09f98(r4, @selector(setIsFetchingStreamInfo:), 0x0);
          loc_e09f98(r4, @selector(setGetStreamRetryIndex:), 0x0);
          r2 = loc_e09f98(r4, @selector(commentRefreshInterval));
          loc_e09f98(r4, @selector(setCommentInterval:), r2);
          loc_e09f98(TTFShareHelper, @selector(setCurrentQuizShowLiveRoomViewModel:), r4);

    } r0 = r4; return r0; }

  • (void)dealloc { var_0 = self; var_4 = *0x2352ee8; r0 = loc_e09fa0(sp - 0x8, @selector(dealloc), 0x23307dc); return; }

  • (void)setCurSignCount:(id)arg2 { STK35 = r7; r7 = &arg_C; STK37 = r8; sp = sp + 0xfffffffffffffffc - 0x4; r8 = self; r0 = objc_ivar_offset_TTFQuizShowLiveRoomViewModel__curSignCount; (r8 + r0) = arg2; *0x88 = r3; var_0 = r3; loc_e09f98(NSString, @selector(stringWithFormat:), cfstring__, arg2, STK37, lr, STK35, r6, r5, r4); r5 = loc_e09f9c(); loc_e09f98(r8, @selector(curSignCountStr)); r7 = r7; r6 = loc_e09f9c(); r1 = @selector(isEqualToString:); r4 = loc_e09f98(r5, r1, r6); loc_e09f94(r6); if (r4 == 0x0) {

    r1 = @selector(setCurSignCountStr:);
          loc_e09f98(r8, r1, r5);

    } r0 = r5; Pop(); Pop(); Pop(); Pop(); Pop(); r0 = loc_1be412c(r0, r1); return; } @end ```

附件: