DDCTFRre3-虚拟指令分析
拿到这个题目是个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-虚拟指令分析相关推荐
- JVM指令分析实例四(数组、switch)
本篇为<JVM指令分析实例>的第四篇,相关实例均使用Oracle JDK 1.8编译,并使用javap生成字节码指令清单. 前几篇传送门: JVM指令分析实例一(常量.局部变量.for循环 ...
- 自学linux指令分析-cat
自学linux指令分析-cat 1·命令格式 cat [OPTION]... [FILE]... cat [参数][文件名] 2·命令参数 -n --number ...
- 自学linux指令分析-find
自学linux指令分析-find 1·命令格式 find pathname -options [-print -exec -ok ...] find / -type f -name "fre ...
- 【计算机系统设计】实践笔记(3)改进数据通路:jr指令分析与实现
1 jr指令分析 instruction op rs rt rd shamt func jr 000000 rs 00000 00000 00000 001000 举例:jr $31 功能:PC &l ...
- 【计算机系统设计】实践笔记(3)改进数据通路:移位R型指令分析
0 回顾 前面的内容中,第一类R型指令分析,我们完成了一类R型指令的设计,完成了其数据通路,构建了相应的部件,并且完成了从ROM中取指,成功进行了基本的功能仿真,进行了综合和实现,但是没有完成综合和实 ...
- 【计算机系统设计】实践笔记(2)数据通路构建:第一类R型指令分析(2)
待办事项 时钟频率高,取指周期长,远大于执行周期,如何处理? 不可综合逻辑的处理 接上一篇 [计算机系统设计]实践笔记(2)数据通路构建:第一类R型指令分析(1) 8.2 ALU运算器 `timesc ...
- 【计算机系统设计】实践笔记(2)数据通路构建:第一类R型指令分析(1)
0 回顾 上一次实践笔记(0)我们实现了一个最简单的,能够每个上升沿+4的PC. 我们最需要关注的就是器件功能的独立性,避免内外功能混杂,同时一定要注意脑中有电路(RTL级描述的抽象电路而不是实际的门 ...
- 自学linux指令分析-mkdir
自学linux指令分析-mkdir 1·命令格式 mkdir [option] [directory-list] mkdir [参数][目录名] 2·命令参数 使用帮助命令:man mkdir或mkd ...
- jmpi 与ljmp指令分析
原文链接 jmpi与ljmp指令分析 jmpi与ljmp都是段间跳转指令 jmpi的格式是: jmpi 段内偏移,段选择子 ljmp的格式是: ljmp 段选择子,段内偏移 jmpi是linux下in ...
- 31条指令单周期cpu设计(Verilog)-(三)指令分析
说在前面 开发环境:Vivado 语言:Verilog cpu框架:Mips 控制器:组合逻辑 鸽鸽鸽... 指令分析流程 确定一条指令所需要的具体操作 分析该条指令涉及的部件 确定各个部件的输入输出 ...
最新文章
- 如何释放电脑被限制的20%网速?
- springboot+mybatis+shiro——shiro简介
- HikariCP--一款高性能的 JDBC 连接池
- 写在这个公众号关注者达到7000之际,Jerry有话对大家说
- 【系统架构设计师】2020-08-06
- win7如何调整计算机c盘,Win7系统增加C盘空间的方法
- 极限学习机(Extreme Learning Machine,ELM)详解
- PHP求100-1000之间的水仙花数
- after meet KeyNi liu
- 虚拟路由冗余协议(VRRP)
- 如何用Java微信扫码实现签到_详解JAVA后端实现统一扫码支付:微信篇
- 深入理解GO语言:GC原理及源码分析
- leetcode (Image Smoother)
- 常用数据指标缩写以及说明(uv、pv、br、cr、dau……):
- Python 基于sicpy求解定积分 ,不定积分以及多重积分
- 解决SQL Server占用服务器内存过高问题
- android计算器开发
- 【洛谷1144】最短路计数 最短路
- React Native 集成极光推送 jpush-react-native
- Group Lasso-Based Band Selection for Hyperspectral Image Classification
热门文章
- pg比mysql优势_postgresql比mysql有多少优势
- java qq 传送文件_java 传送文件
- 微信小程序全国巡回沙龙杭州站-芋头演讲详细内容及PPT
- kafka自动提交offset的设置理解
- 光辉岁月-Beyond_习惯累积沉淀_新浪博客
- 代数结构与有限域之 群
- 百度语音识别开放平台SDK使用方法
- 一篇几乎涵盖95%英语语法的文章[Pending]
- FIRST集合、FOLLOW集合以及LL(1)文法
- 黑马头条项目-Vue-day10-小智同学聊天功能,退出功能的实现,websocket用法,白名单,关于nextTick()方法