拿到这个题目是个MAC题放入IDA中分析,右侧找到了checkcode函数,进入这个函数

void __cdecl -[ViewController checkCode:](ViewController *self, SEL a2, id a3)
{void *v3; // raxvoid *v4; // raxvoid *v5; // ST18_8void *v6; // raxchar *v7; // raxvoid *v8; // raxchar *v9; // raxvoid *v10; // raxvoid *v11; // raxvoid *v12; // [rsp+38h] [rbp-58h]void *v13; // [rsp+40h] [rbp-50h]__int128 input; // [rsp+48h] [rbp-48h]__int64 v15; // [rsp+58h] [rbp-38h]SEL v16; // [rsp+60h] [rbp-30h]void *v17; // [rsp+68h] [rbp-28h]char *v18; // [rsp+70h] [rbp-20h]__int64 v19; // [rsp+78h] [rbp-18h]__int64 v20; // [rsp+80h] [rbp-10h]char *v21; // [rsp+88h] [rbp-8h]v17 = self;v16 = a2;v15 = 0LL;objc_storeStrong((__int64)&v15, (__int64)a3);v3 = objc_msgSend(v17, "pwd");v4 = (void *)objc_retainAutoreleasedReturnValue(v3);v5 = v4;v6 = objc_msgSend(v4, "stringValue");input = (unsigned __int64)objc_retainAutoreleasedReturnValue(v6);objc_release(v5);if ( (unsigned __int8)objc_msgSend((void *)input, "hasPrefix:", CFSTR("DDCTF{")) ){v7 = (char *)objc_msgSend((void *)input, "length");v8 = objc_msgSend((void *)input, "substringFromIndex:", v7 - 1);v13 = (void *)objc_retainAutoreleasedReturnValue(v8);if ( (unsigned __int8)objc_msgSend(v13, "isEqualToString:", CFSTR("}")) ){v9 = (char *)objc_msgSend((void *)input, "length");v19 = 6LL;v18 = v9 - 7;v20 = 6LL;v21 = v9 - 7;v10 = objc_msgSend((void *)input, "substringWithRange:", 6LL, v9 - 7);v12 = (void *)objc_retainAutoreleasedReturnValue(v10);if ( objc_msgSend(v12, "length") == (void *)18 ){v11 = (void *)objc_retainAutorelease((__int64)v12);*((_QWORD *)&input + 1) = objc_msgSend(v11, "UTF8String");}objc_storeStrong((__int64)&v12, 0LL);}objc_storeStrong((__int64)&v13, 0LL);}if ( *((_QWORD *)&input + 1) ){if ( (unsigned int)sub_1000011D0(*((__int64 *)&input + 1)) == 1 )objc_msgSend(v17, "onSuccess");elseobjc_msgSend(v17, "onFailed");}else{objc_msgSend(v17, "onFailed");}objc_storeStrong((__int64)&input, 0LL);objc_storeStrong((__int64)&v15, 0LL);
}

看到了最后的onsucess和onfailed是于是上面这个判断就很关键,进入判断函数。

__int64 __fastcall sub_1000011D0(__int64 input)
{char virtual_1; // [rsp+20h] [rbp-C0h]__int64 v3; // [rsp+D8h] [rbp-8h]v3 = input;memset(&virtual_1, 0, 0xB8uLL);sub_100001F60((__int64)&virtual_1, input);    // 初始化虚拟机return (unsigned int)sub_100001F00((__int64)&virtual_1);// 返回结果为1
}

分析第一个函数

__int64 __fastcall sub_100001F60(__int64 vitrual_1, __int64 input)
{*(_DWORD *)vitrual_1 = 0;*(_DWORD *)(vitrual_1 + 4) = 0;*(_DWORD *)(vitrual_1 + 8) = 0;*(_DWORD *)(vitrual_1 + 12) = 0;*(_DWORD *)(vitrual_1 + 16) = 0;*(_DWORD *)(vitrual_1 + 176) = 0;*(_BYTE *)(vitrual_1 + 32) = -16;*(_QWORD *)(vitrual_1 + 40) = sub_100001D70;*(_BYTE *)(vitrual_1 + 48) = -15;*(_QWORD *)(vitrual_1 + 56) = sub_100001A60;*(_BYTE *)(vitrual_1 + 64) = -14;*(_QWORD *)(vitrual_1 + 72) = sub_100001AA0;*(_BYTE *)(vitrual_1 + 80) = -12;*(_QWORD *)(vitrual_1 + 88) = sub_100001CB0;*(_BYTE *)(vitrual_1 + 96) = -11;*(_QWORD *)(vitrual_1 + 104) = sub_100001CF0;*(_BYTE *)(vitrual_1 + 112) = -13;*(_QWORD *)(vitrual_1 + 120) = sub_100001B70;*(_BYTE *)(vitrual_1 + 128) = -10;*(_QWORD *)(vitrual_1 + 136) = sub_100001B10;*(_BYTE *)(vitrual_1 + 144) = -9;*(_QWORD *)(vitrual_1 + 152) = sub_100001D30;*(_BYTE *)(vitrual_1 + 160) = -8;*(_QWORD *)(vitrual_1 + 168) = sub_100001C60;qword_100003F58 = malloc(0x400uLL);return __memcpy_chk((__int64)qword_100003F58 + 0x30, input, 18LL, -1LL);// 复制内存区域
}

发现是一系列的赋值和函数地址和最后一片input的复制
退出来再看第二个函数以第一个函数赋值的地址作为参数传入,进入该函数

__int64 __fastcall sub_100001F00(__int64 virtual_1)
{*(_QWORD *)(virtual_1 + 24) = (char *)&unk_100001980 + 4;// *virtual1+24为100001984while ( **(unsigned __int8 **)(virtual_1 + 24) != 0xF3 )sub_100001E50(virtual_1);free(qword_100003F58);                        // 1003F58为输入的值return *(unsigned int *)(virtual_1 + 176);
}

首先*virtul1+24的值为100001984即为F0不为F3继续向下走。进入100001E50.

bool __fastcall sub_100001E50(__int64 virtual_1)
{bool result; // albool v2; // [rsp+Fh] [rbp-11h]signed int v3; // [rsp+10h] [rbp-10h]signed int v4; // [rsp+14h] [rbp-Ch]v4 = 0;v3 = 0;while ( 1 ){v2 = 0;if ( !v4 )v2 = v3 < 9;result = v2;if ( !v2 )                                  // 如果v3大于等于9,且v4为1 则退出循环break;if ( **(unsigned __int8 **)(virtual_1 + 24) == *(unsigned __int8 *)(16LL * v3 + virtual_1 + 32) )// F0等于-16{v4 = 1;(*(void (__fastcall **)(__int64))(16LL * v3 + virtual_1 + 32 + 8))(virtual_1);// 第一个字符0为参数,执行1D70函数}else{++v3;}}return result;
}

v3为0小于9成立进入判断**(virtual1+24)的值为F0等于virul1+32的值(unsigned)-16.执行virtual1+40的函数为100001D70

__int64 __fastcall sub_100001D70(__int64 virtual_1)
{__int64 result; // raxsigned int *v2; // [rsp+Ch] [rbp-18h]v2 = (signed int *)(*(_QWORD *)(virtual_1 + 24) + 2LL);// 第一个字符为0x66switch ( *(unsigned __int8 *)(*(_QWORD *)(virtual_1 + 24) + 1LL) )// 后一个字符判断{case 0x10u:*(_DWORD *)virtual_1 = *v2;               // 改变a1第一个值break;case 0x11u:*(_DWORD *)(virtual_1 + 4) = *v2;break;case 0x12u:*(_DWORD *)(virtual_1 + 8) = *v2;break;case 0x13u:*(_DWORD *)(virtual_1 + 12) = *v2;break;case 0x14u:*(_DWORD *)virtual_1 = *((char *)qword_100003F58 + *v2);break;default:break;}result = virtual_1;*(_QWORD *)(virtual_1 + 24) += 6LL;           // virtual+24的值加6return result;
}

v2等于100001984的后两位的取值为0x66,在对100001984的后一位为0x10进行判断,把0x66(f)赋值给virtual_1,之后virual1+24的值向后移动6位。然后再次执行10001E50,**(virtual1+24)的值位F8,要使其相等v3的值 16v3+32的值要为160,那么执行的函数就是 *(virtual1+68)为1c60进入这个函数

__int64 __fastcall sub_100001C60(__int64 vitrual_1)
{__int64 result; // raxresult = sub_100001B80(*(_DWORD *)vitrual_1, 2);*(_DWORD *)vitrual_1 = (char)result;          // 第一个字符变成h++*(_QWORD *)(vitrual_1 + 24);return result;
}

分析10001B80,就是将字符

__int64 __fastcall sub_100001B80(char virtual_1, int a2)
{bool v3; // [rsp+7h] [rbp-11h]bool v4; // [rsp+Fh] [rbp-9h]char v5; // [rsp+17h] [rbp-1h]v4 = 0;if ( virtual_1 >= 'A' )v4 = virtual_1 <= 'Z';if ( v4 ){v5 = (a2 + virtual_1 - 'A') % 26 + 65;}else{v3 = 0;if ( virtual_1 >= 'a' )v3 = virtual_1 <= 'z';                    // 第一个字符为fif ( v3 )v5 = (a2 + virtual_1 - 'a') % 26 + 97;    // v5为helsev5 = virtual_1;}return (unsigned int)v5;
}

就是将第字符+2,virtual1处字符变成h,(virtual1+24)的值+1, **(virtual1+24)的值为F2再看1E50函数32+16v3的值要为-14后面执行1AA0的函数

__int64 __fastcall sub_100001AA0(__int64 virtual_1)
{__int64 result; // rax*(_DWORD *)(virtual_1 + 16) = *(_DWORD *)virtual_1 == *((char *)qword_100003F58+ *(unsigned __int8 *)(*(_QWORD *)(virtual_1 + 24) + 1LL));// 判断input值必须要等于h,后一个字符必须要等于eresult = virtual_1;*(_QWORD *)(virtual_1 + 24) += 2LL;return result;
}

如果input1值与virual1的值不相等*(virual1+16)的值为0,否则为1,指令再向后移动2个到了f6等于-10执行1b10

__int64 __fastcall sub_100001B10(__int64 virtual_1)
{__int64 result; // raxif ( *(_DWORD *)(virtual_1 + 16) )*(_DWORD *)(virtual_1 + 16) = 0;else*(_QWORD *)(virtual_1 + 24) += *(unsigned __int8 *)(*(_QWORD *)(virtual_1 + 24) + 1LL);result = virtual_1;*(_QWORD *)(virtual_1 + 24) += 2LL;return result;
}

判断a1+16是否为0如果为0,指令向后移动为后一个字节码的值C1再向后移动2位到了地址到了1a50为f7.f7为-9执行1D30函数。

__int64 __fastcall sub_100001D30(__int64 virtual_1)
{__int64 result; // raxresult = *(unsigned int *)(*(_QWORD *)(virtual_1 + 24) + 1LL);*(_DWORD *)(virtual_1 + 176) = result;*(_QWORD *)(virtual_1 + 24) += 5LL;return result;
}

返回值为0,字节码向后移动5位,字节码为F3,返回结果并不为1,所以必须要等于相等,之后即可得到第一个字符为h.
继续向下分析即可得到全部字符

DDCTFRre3-虚拟指令分析相关推荐

  1. JVM指令分析实例四(数组、switch)

    本篇为<JVM指令分析实例>的第四篇,相关实例均使用Oracle JDK 1.8编译,并使用javap生成字节码指令清单. 前几篇传送门: JVM指令分析实例一(常量.局部变量.for循环 ...

  2. 自学linux指令分析-cat

    自学linux指令分析-cat 1·命令格式 cat [OPTION]... [FILE]... cat [参数][文件名] 2·命令参数 -n                    --number ...

  3. 自学linux指令分析-find

    自学linux指令分析-find 1·命令格式 find pathname -options [-print -exec -ok ...] find / -type f -name "fre ...

  4. 【计算机系统设计】实践笔记(3)改进数据通路:jr指令分析与实现

    1 jr指令分析 instruction op rs rt rd shamt func jr 000000 rs 00000 00000 00000 001000 举例:jr $31 功能:PC &l ...

  5. 【计算机系统设计】实践笔记(3)改进数据通路:移位R型指令分析

    0 回顾 前面的内容中,第一类R型指令分析,我们完成了一类R型指令的设计,完成了其数据通路,构建了相应的部件,并且完成了从ROM中取指,成功进行了基本的功能仿真,进行了综合和实现,但是没有完成综合和实 ...

  6. 【计算机系统设计】实践笔记(2)数据通路构建:第一类R型指令分析(2)

    待办事项 时钟频率高,取指周期长,远大于执行周期,如何处理? 不可综合逻辑的处理 接上一篇 [计算机系统设计]实践笔记(2)数据通路构建:第一类R型指令分析(1) 8.2 ALU运算器 `timesc ...

  7. 【计算机系统设计】实践笔记(2)数据通路构建:第一类R型指令分析(1)

    0 回顾 上一次实践笔记(0)我们实现了一个最简单的,能够每个上升沿+4的PC. 我们最需要关注的就是器件功能的独立性,避免内外功能混杂,同时一定要注意脑中有电路(RTL级描述的抽象电路而不是实际的门 ...

  8. 自学linux指令分析-mkdir

    自学linux指令分析-mkdir 1·命令格式 mkdir [option] [directory-list] mkdir [参数][目录名] 2·命令参数 使用帮助命令:man mkdir或mkd ...

  9. jmpi 与ljmp指令分析

    原文链接 jmpi与ljmp指令分析 jmpi与ljmp都是段间跳转指令 jmpi的格式是: jmpi 段内偏移,段选择子 ljmp的格式是: ljmp 段选择子,段内偏移 jmpi是linux下in ...

  10. 31条指令单周期cpu设计(Verilog)-(三)指令分析

    说在前面 开发环境:Vivado 语言:Verilog cpu框架:Mips 控制器:组合逻辑 鸽鸽鸽... 指令分析流程 确定一条指令所需要的具体操作 分析该条指令涉及的部件 确定各个部件的输入输出 ...

最新文章

  1. 如何释放电脑被限制的20%网速?
  2. springboot+mybatis+shiro——shiro简介
  3. HikariCP--一款高性能的 JDBC 连接池
  4. 写在这个公众号关注者达到7000之际,Jerry有话对大家说
  5. 【系统架构设计师】2020-08-06
  6. win7如何调整计算机c盘,Win7系统增加C盘空间的方法
  7. 极限学习机(Extreme Learning Machine,ELM)详解
  8. PHP求100-1000之间的水仙花数
  9. after meet KeyNi liu
  10. 虚拟路由冗余协议(VRRP)
  11. 如何用Java微信扫码实现签到_详解JAVA后端实现统一扫码支付:微信篇
  12. 深入理解GO语言:GC原理及源码分析
  13. leetcode (Image Smoother)
  14. 常用数据指标缩写以及说明(uv、pv、br、cr、dau……):
  15. Python 基于sicpy求解定积分 ,不定积分以及多重积分
  16. 解决SQL Server占用服务器内存过高问题
  17. android计算器开发
  18. 【洛谷1144】最短路计数 最短路
  19. React Native 集成极光推送 jpush-react-native
  20. Group Lasso-Based Band Selection for Hyperspectral Image Classification

热门文章

  1. pg比mysql优势_postgresql比mysql有多少优势
  2. java qq 传送文件_java 传送文件
  3. 微信小程序全国巡回沙龙杭州站-芋头演讲详细内容及PPT
  4. kafka自动提交offset的设置理解
  5. 光辉岁月-Beyond_习惯累积沉淀_新浪博客
  6. 代数结构与有限域之 群
  7. 百度语音识别开放平台SDK使用方法
  8. 一篇几乎涵盖95%英语语法的文章[Pending]
  9. FIRST集合、FOLLOW集合以及LL(1)文法
  10. 黑马头条项目-Vue-day10-小智同学聊天功能,退出功能的实现,websocket用法,白名单,关于nextTick()方法