第一,分享位置到微信。
第二,点击分享微信的图片。
第三,在右上角上点开“…”,点击在浏览器中打开。
第四,点击浏览器右下角“::”。
第五,点击分享。
第六,分享至微信。
第七,第一行等号后的两个长数字就是经纬度(坐标)
本文主要记录了逆向分析国外某地图APP的坐标系加解密算法的还原过程,从抓包特征开始, 一步一步定位到关键加解密函数。
在加解密函数分析过程中遭遇ARM NEON向量指令集, 不得不使用动态调试定位该指令集处, 但又遭遇反调试,导致加载目标进程直接退出, 之后开始分析反调试过程, 针对性的进行打补丁。
通过动态调试终于拿到ARM NEON向量指令集四轮密钥变换之后保存在内存中的关键密钥,并使用函数参数HOOK方式拿到加密字符串和解密字符串, 这样我在本地将算法还原后可以验证还原的算法是否准确。
在拿到密钥之后我在本地使用C语言进行了算法代码还原, 最后经过验证在本地成功解密出明文坐标信息。
逆向分析思路我的逆向分析思路概括起来主要包括以下几个过程:
全方位使用软件功能,同时打开Wireshark进行抓包, 等所有功能差不多全部点击完成时, 保存好抓包文件通过分析抓包文件, 整理出一些比较明显未加密的特征,例如: 本文中代表经纬度的关键参数:&longitude=&latitude=利用静态分析工具IDA加载可执行程序, 使用快捷键shift+F12调出字符串查找窗口,搜索上面的关键参数利用IDA的交叉引用功能尽量找到关键参数对应的调用函数位置, 如果无法定位到有效的函数,可以尝试其它参数搜索利用关键参数找到的所有可疑函数记录下来, 第一轮先静态分析, 利用IDA的F5功能快速将汇编代码进行高级语言伪代码转换,提高分析效率。第二轮将筛选出来的高可疑函数使用函数参数HOOK, 通过打印出来的参数内容验证自己的想法。在静态分析中遇到无法从IDA中直接扣代码或晦涩的汇编指令, 使用动态调试进行断点跟踪验证。在本地使用高级语言将分析出来的函数逻辑进行代码组织, 验证流程。前期分析在经过一段时间的前期反复使用和抓包分析, 最终定位到以下参数很可能是加密后的坐标系信息上传数据包:
抓取的加密后的坐标数据包内容
通过其它功能接口的使用, 整理出一组关键的频率比较高的特征:&longitude=、&latitude=
在前期尽量能多收集一些关键特征, 经过分析整理后进行优先级排序, 方便为后面的静态分析做准备。
静态分析使用静态反汇编工具IDA加载软件的二进制程序, 由于程序比较大, 在经过比较长时间的加载分析之后, 使用快捷键shift+F12调出IDA的字符串查找窗口, 输入上面的关键字符串进行搜索查找,最终在庞大的软件中找到该处:
通过IDA全局搜索字符串
直接双击该字符串,利用IDA的交叉引用功能,可以发现以下函数进行了调用:
利用IDA的交叉引用定位调用函数
函数对应的类名为:NMXXTEAEncrypt,函数名为:testXXTEA
立即到IDA的Functions window窗口进行搜索,发现有以下函数:
在函数窗口中搜索函数名称
看来字符串很可能是通过xxTEA算法进行加解密的, 先了解下XXTEA算法是什么。
XXTEA算法特征如下:
速度快。XXTEA算法经过优化,执行速度很快,可以在现代计算机上每秒进行几十亿次加密。这使其可以应用在对性能要求较高的场景体积小。XXTEA算法只需要包括两个尺寸小的表(每个4K),因此代码实现也非常小巧和紧凑。这使其可以应用在代码空间有限的场景安全性高。尽管简单,但XXTEA具有非常高的安全强度。它采用128位密钥,能够抵御所有已知的密码分析攻击易于实现。XXTEA算法设计简单,易于理解和实现。这使其可以很容易地应用到各种硬件和软件平台开源免费。XXTEA算法是开源的,任何人都可以自由使用,不需要支付授权费用广泛支持。现在大多数平台和编程语言都有XXTEA的实现,使其很容易集成使用加密安全性高。XXTEA采用加密模式可以确保数据的保密性。不同于只提供校验的哈希算法这里直接双击XXTEA的解密算法xxTeaDecryptString函数, 并利用IDA的F5功能进行高级语言伪代码生成,代码如下:
在解密函数中找到关键函数调用
在上图中, 发现有一个关键的函数调用方法, 名为:sub_4C2408, 双击进入该函数内部, 如图所示:
进入sub_4C2408子函数内部
种种迹象表明, 该函数看起来像是在做算法运算, 而其中包含两个关键子函数:sub_4C2498和sub_4C20E0, 先看第一个,双击进入函数sub_4C2498内部, 如图:
进入sub_4C2498子函数内部
看关键操作,像是Base64的特征,不过里面没有其它函数调用, 像这个纯算法到时候可以直接拿出来使用。
接着进入第二个函数sub_4C20E0内部,如图:
进入sub_4C20E0函数内部
这里看到了一些让人懵圈的东西, 像这种奇怪的指令是没办法直接扣出来使用的, 回到IDA View窗口看看都是些什么指令,如图:
晦涩难懂的汇编指令
根据查询, 这些指令是ARM NEON向量指令集, 看下ARM NEON向量指令集介绍:
ARM NEON 是 ARM 架构中的一个 SIMD (单指令多数据) 向量处理指令集。它具有以下特点和作用:
提供了128比特的向量寄存器,可以加速多媒体和信号处理运算。支持整数和单精度浮点向量运算,如加、减、乘、除、饱和、打包、解包等。包含矩阵变换和乘法指令,可以加速图像处理。支持多种数据类型:8位整数、16位整数、32位整数、32位浮点数。可以并行进行同一指令操作的向量计算,提升计算性能。编译器优化时可以自动利用NEON指令提升性能,无需人工优化。保持了与ARM标量指令的兼容性,同时使用标量和向量指令。应用场景包括图像处理、音频编解码、3D图形、信号处理、科学计算等。被广泛应用于移动设备、嵌入式系统等对计算性能要求高的场景。这样的指令集不知道里面在做些什么操作, 只能使用动态调试的方法去看内存了。
处理反调试在经过一顿操作猛如虎的环境搭建和配置后, 兴奋的附加到目标进程, 但却屡屡收到噩耗,如图所示:
附加进程频繁退出
看样子是不想让我附加进程, 回到IDA, 在程序入口处发现以下代码,如图所示:
找到反调试的地方
Ptrace()系统调用被用来实现反调试保护,原理如下:
在目标程序启动初期,调用 ptrace(PT_DENY_ATTACH, 0, 0, 0) 禁止其他进程附加随后再调用 ptrace(PT_TRACE_ME, 0, 0, 0) 对自身进程跟踪如果该调用失败,说明当前进程已经被调试器附加,出现反调试情况如果成功,则一直循环调用 wait() 等待被其他进程跟踪如果 wait() 返回,则同样表示有反调试行为程序可以通过检查 ptrace() 调用的返回值来判断是否出现了反调试情况,并作出相应反应针对该原理, 我使用了以下代码进行了绕过:
int fake_ptrace(int request,pid_t pid,caddr_t addr,int data){ return 0;}void*(*old_dlsym)(void* handle,const char* symbol);void* my_dlsym(void* handle,const char* symbol){ if(strcmp(symbol,"ptrace") == 0) { return (void*)fake_ptrace; } return old_dlsym(handle,symbol);}%ctor{ @autoreleasepool { MSHookFunction((void*)dlsym,(void*)my_dlsym,(void**)&old_dlsym); }}
大致意思就是利用Hook框架对原ptrace()函数进行挂钩, 然后对该函数进行处理, 让他调用我的假ptrace()函数。
下面终于可以愉快的动态调试了。
动态调试动态调试的过程跟普通调试方法差不多, 熟练使用单步指令、下断点就行, 以下是从ARM NEON指令集中动态解出密钥:
动态解出密钥信息
为了能得到加密函数和解密函数的传参内容, 我使用了类似以下的代码进行了函数参数Hook:
%hook NMXXTEAEncrypt+ (id)xxTeaEncryptString:(id)arg1{id r = %orig();id r1 = arg1;NSLog(@"=========================================================");NSLog(@"NMXXTEAEncrypt::xxTeaEncryptString");NSLog(@"=========================================================");NSLog(@"Encrypt return value = %@", r);NSLog(@"data value = %@", r1);return r;}%end
Hook后的效果非常不错, 软件自动把加密后的字符串和解密后的字符串自动打印出来了,如图:
Hook函数参数后打印出高价值信息
算法还原首先还原上面的子函数:sub_4C2408, 还原的代码如下:
void* decrypt_func(const void* data, unsigned int data_length, int key){ int v1; unsigned int v6; void* v7; BYTE* v8; void* v9; signed int v10; int v17; signed int v18; size_t v19; v1 = (int)data; v6 = data_length; v7 = 0; if(v1 && data_length >= 5) { v8 = base64_decode(v1,data_length); v9 = malloc(0x10u); v10 = 3 * (v6 >> 2); if(xxtea_decrypt((unsigned int*)v8, v10/-4, (int)key) == 1) { while(v10 >= 2) { v17 = v10 - 1; v18 = v8[v10-- - 1]; if ( v18 >= 1 ) { v19 = v17 - v18 + 1; v7 = malloc(v19); //*v4 = v19; memcpy(v7, v8, v19); goto LABEL_8; } } v7 = 0; }LABEL_8: free(v8); free(v9); } return v7;}
其次还原子函数sub_4C2498,源码如下:
BYTE* base64_decode(int data, unsigned int data_size){ unsigned int v2; // r6@1 int v3; // r0@1 signed int v4; // r2@1 signed int v5; // r4@1 int v6; // r10@5 size_t v7; // r5@5 BYTE *v8; // r0@11 BYTE *v9; // r8@11 unsigned int v10; // r0@13 unsigned int v11; // r2@13 unsigned int v12; // r10@17 int v13; // r5@17 BYTE *v14; // r8@17 int v15; // r4@17 int v16; // r1@19 int v17; // r11@21 int v18; // t1@22 int v19; // r9@26 signed int v20; // r2@26 signed int v21; // r0@26 BYTE *v22; // r3@26 signed int v23; // r5@27 int v25; // [sp+0h] [bp-34h]@15 int v26; // [sp+4h] [bp-30h]@15 int v27; // [sp+8h] [bp-2Ch]@13 BYTE *v28; // [sp+Ch] [bp-28h]@11 int v29; // [sp+10h] [bp-24h]@1 BYTE *v30; // [sp+14h] [bp-20h]@12 int v31; // [sp+18h] [bp-1Ch]@1 int v32; // [sp+18h] [bp-1Ch]@21 char number_array[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; v2 = data_size; v29 = data; v3 = data + data_size; v4 = 1; v5 = 0; v31 = *(BYTE *)(v3 - 3); if ( *(BYTE *)(v3 - 1) == 61 ) { v4 = 2; v5 = 1; } if ( *(BYTE *)(v3 - 2) == 61 ) v5 = v4; v6 = v5; v7 = 3 * (data_size >> 2); if ( *(BYTE *)(v3 - 3) == 61 ) v6 = v5 + 1; switch ( v6 ) { case 0: case 1: v7 += 4; break; case 2: v7 += 3; break; case 3: v7 += 2; break; default: break; } v8 = malloc(v7); v9 = v8; v28 = v8; if ( !v8 ) { puts("No enough memory."); exit(0); } memset(v8, 0, v7); v30 = v9; if ( v6 != v2 ) { v10 = v2 - v6; v27 = v2 - v6; v11 = 0; if ( v31 == 61 ) ++v5; v26 = v5 - v2; v25 = v6 - v2; v30 = v9; do { if ( v11 < v10 ) { v12 = -4; v13 = 0; v14 = (BYTE *)(v29 + v11); v15 = v25 + v11; if ( v25 + v11 > 0xFFFFFFFC ) v12 = v25 + v11; v16 = v26 + v11; if ( v26 + v11 <= 0xFFFFFFFC ) v16 = -4; v17 = -v16; v32 = v11 - v12; do { v18 = *v14++; --v17; v13 = (char)&strrchr(number_array, v18)[-(unsigned int)number_array] | (v13 << 6); } while ( v17 ); v9 = v28; if ( v12 ) { if ( v12 <= 0xFFFFFFFD ) v15 = -3; v19 = -v15; v20 = 16; v21 = v13 << (6 * v12 + 24); v22 = v30; do { v23 = v21 >> v20; v20 -= 8; *v22++ = v23; ++v15; } while ( v15 ); v30 += v19; } v10 = v27; v11 = v32; } } while ( v11 < v10 ); } *v30 = 0; return v9;}
继续还原第二个子函数sub_4C20E0:
signed int xxtea_decrypt(unsigned int *data, signed int data_size, int decrypt_key){ signed int v3; unsigned int v10; int v14; unsigned int v27; signed int v28; unsigned int *v29; int v30; int v31; unsigned int v32; int v33; int v34; unsigned int v35; int v36; unsigned int *v37; v3 = data_size; v10 = *data; v37 = data; v14 = decrypt_key; if(v3 < 2) { if(v3 >= -1) { return 0; } v36 = -v3; v27 = 2654435769 * (52 / -v3) + 3041712726; if ( v27 != 0 ) { v28 = v3; v29 = v37; v30 = ~v28; v31 = v14; do { v32 = v29[v30]; v33 = (v27 >> 2) & 3; v34 = v36; do { v35 = v37[v34 - 2]; v10 = v32 - (((16 * v35 ^ (v10 >> 3)) + ((v35 >> 5) ^ 4 * v10)) ^ ((*(unsigned long*)(v31 + 4 * ((v34 - 1) & 3 ^ v33)) ^ v35) + (v10 ^ v27))); v37[v34-- - 1] = v10; v32 = v35; } while (v34 >= 2); v29 = v37; v30 = ~v28; v10 = *v37 - ((((v37[~v28] >> 5) ^ 4 * v10) + (16 * v37[~v28] ^ (v10 >> 3))) ^ ((*(unsigned long*)(v31 + 4 * v33) ^ v37[~v28]) + (v10 ^ v27))); v27 += 1640531527; *v37 = v10; } while ( v27 ); } } return 1;}
到此,关键解密函数全部还原出来了, 加密算法与此类似,不再赘述, 最后的代码结构如下:
最终还原代码工程文件
在main函数中,我需要将动态解出来的密钥还有参数传给函数进行加解密,如图:
主函数中的调用逻辑
结果验证将上面的C代码编译后执行, 加密字符串成功被解密了,如图:
成功通过还原的算法进行解密
茂南区是广东省茂名市辖区,位于广东省西南部的粤西地区,因地处原茂名县(今主体分属高州市、茂南区)之南部而得名。地处于东经110°44′—110°58′和北纬21°32′- 21°49′之间,东毗电白,南邻吴川,西接化州,北连高州。
该区共管辖8个街道、9个镇(2017年9月羊角镇划入,另增设城南街道),共辖133个村委会和85个居委会(不含羊角镇),区域总面积达526平方公里(不含羊角镇)。截至2011年底,茂南区有33个民族成分,8千多少数民族人口。
中文名称
茂南区
外文名称
Maonan Qu
行政区类别
市辖区
所属地区
中国·广东省·茂名市
下辖地区
8个街道、9个镇
政府驻地
城南街道城南路138号
电话区号
0668
邮政区码
525000
地理位置
广东省西南部
面 积
526平方千米(不含羊角镇)
人 口
户籍人口84.39万人(2011年)
方 言
粤语-高阳片-茂名白话、雷话、涯话
气候条件
带季风性湿润气候
著名景点
茂名森林公园,鳌头古镇,鳌头水乡桃花德岛,瓦岭福德境
机 场
粤西国际机场
火车站
茂名站,茂名西站,茂名东站
车牌代码
粤K
行政代码
440902
历史沿革
茂名市,秦代属于南海郡地。西汉时,设立高凉县,属于合浦郡高凉县地。
东汉时分合浦郡置高凉郡,属于高凉郡地。三国时属吴国高凉郡高凉县地。
东晋时属高凉郡地。西晋至东晋,当时这高凉地域出现一位名医潘茂名。南北朝时期,梁中大通元年(529年)置高州,陈朝置高州高凉郡,又置高州南巴郡,今茂南属南巴郡地。隋朝将州郡县三级改为州县二级。
隋文帝时,因民众广为传扬潘茂名的业绩,于开皇十八年(598年)新设置茂名县,今茂南属高凉郡(高州)茂名县地。
南北朝、隋朝时,今茂南一带地方也是冼夫人主要活动地。
唐贞观八年(634年)将南宕州更名潘州,州治所在茂名,领茂名、潘水、南巴3县,今茂南属潘水县地(部分属南巴县)。
五代十国时期,后梁开平元年(907年),茂名县更名越裳县,龙德三年(923年)复名茂名县。
北宋开宝五年(972年),废潘州,潘水、南巴两县并入茂名县,今茂南属茂名县地,后略有变动。熙宁四年(1071年),并窦州入高州,领茂名、电白、信宜三县,属广南西路,今茂南属高州茂名县地。元至元十七年(1280年)高州改名为高州路安抚司,大德八年(1304年)高州路治所由电白县(今长坡)迁茂名县(今高州城)。明洪武元年(1368年),高州路改高州府。洪武十四年(1381年),高州府领茂名、电白、信宜和化州原辖县吴川、廉江。
清顺治四年(1647年)高州府属于高雷阳道,领化州和茂名、电白、信宜、吴川、廉江1州5县,府治在茂名县高州城。
明清两朝,今茂南属茂名县地。中华时期,撤高州府,1936年省设置的省第七区领辖8县1局的机构常驻茂名县城(1947年改为省第八区辖7县1局),今茂南区属茂名县南部的二区五区和后改的乡(镇)。
中华人民共和国成立后,茂名县先后属南路专区、高雷专区、粤西行政区、湛江专区,今茂南属这地区的茂名县地。1958年8月26日国务院批准成立茂名工矿区市,1959年5月9日成立茂名市,茂名县南部的公馆、袂花、金塘、新坡、高山、鳌头、镇盛、山阁等镇先后划归茂名市,茂名县改名高州县。1983年实行市管县体制,1985年建置茂南区,属茂名市辖区。
1996年,茂南区辖:河东街道、官渡街道、露天矿街道、河西街道、红旗街道、新华街道、金塘镇、公馆镇、镇盛镇、鳌头镇、袂花镇、高山镇、新坡镇、山阁镇。
2000年第五次人口普查,茂南区(辖7个街道、8个镇)常住总人口644301人,其中:红旗街道26089人,河西街道19406人,河东街道62679人,露天矿街道15634人,新华街道10815人,官渡街道99554人,站前街道30061人,金塘镇57424人,公馆镇57543人,新坡镇33586人,镇盛镇49420人,鳌头镇71818人,袂花镇41160人,高山镇22720人,山阁镇30378人,茂南开发区16014人。
2002年,茂南区辖红旗、河西、河东、新华、官渡、站前、露天矿7个街道和山阁、高山、袂花、新坡、鳌头、镇盛、公馆、金塘8个镇。
2005年末,茂南区辖红旗、河西、河东、新华、官渡、站前、露天矿7个街道和金塘、山阁、高山、袂花、新坡、鳌头、镇盛、公馆8个镇。
2008年末,茂南区户籍总人口807726人。
2009年末,茂南区面积525.6平方千米,辖8个街道、8个镇,79个社区、135个行政村。区政府驻站前街道站前路28号。
2010年第六次人口普查,茂南区常住总人口820821人,其中:红旗街道30888人,河西街道23849人,河东街道93590人,露天矿街道17230人,新华街道11534人,官渡街道158808人,站前街道79575人,金塘镇60774人,公馆镇63792人,新坡镇36699人,镇盛镇53847人,鳌头镇70459人,袂花镇40844人,高山镇16750人,山阁镇31037人,茂南开发区31145人。
2012年末,茂南区辖8个镇、7个街道和1个城郊经济开发试验区,面积487平方千米,户籍人口84.4万人,常住人口83.6万人。
2017年9月,原属电白区的羊角镇划入茂南区管辖,另增设城南街道,至此茂南区管辖8个街道、9个镇。
风景旅游
茂南区有国家4旅游景区茂名森林公园、鳌头古镇、鳌头水乡桃花岛、公馆灵惠寺、福德境、年代记忆收藏馆,恐龙蛋化石人文景观。
规划开发中的主要景点有:镇盛青年湖、山阁温泉、茂名乐天大酒店、茂南湿地公园、茂名市罗非鱼养殖科普旅游示范基地、飞马园椒农业观光旅游示范基地、燕山生态民俗园、丰利·鸽天下农家庄园、茂名大溪水乡风情旅游区、袂花北斗湾生态农家庄园和百里江堤生态景观长廊等。区内有五星级酒店1家、四星级酒店2家,三星级酒店3家。[19]
主要景点
茂名森林公园
茂名森林公园
广东茂名森林公园是国家4旅游景区,是茂名市唯一的省级森林公园,公园位于茂名市茂南区西郊,距市区12公里。公园总体规划本着“以森林为主,以引进新、奇、特南带植物为主,以科普教育为主”的原则,分为森林休闲区、科普教育区和文化娱乐区。
茂名露天矿生态公园
茂名露天矿,位于金塘镇东南部,是茂名市区西北角一个面积达10.07平方公里、最深处距地表超过百米——中国第二大、南方最大的露天矿坑,为共和国石油工业做出重要贡献的油页岩矿,从卫星上俯瞰茂名,在城区西北角呈现出一块巨大的“疤痕”。
2013年12月31日,茂名露天矿移交茂名市政府。2014年初,茂名露天矿生态公园建设拉开序幕。引水工程在2014年10月动工,2016年3月31日正式通水,将高州水库、鉴江水源注入矿坑湖,将持续引水200多天,到2016年10月份矿坑湖库容逐渐达到1.6亿立方米,使矿坑湖水体面积达6.8平方公里。[26]
在引水的同时,开始了修路。2017年年底,环公园路网已建设里程34.68公里,含环绕好心湖主线15.29公里、支线19.39公里。
2017年年底露天矿生态公园已初具规模,逐渐展现出碧波荡漾、苍翠欲滴、繁花似锦、鸟儿啾鸣、文化荟萃、游人如织的休闲娱乐美景。
鳌头古镇
鳌头古镇
鳌头古镇始建于明朝洪武年间,建制已有500多年,是历史文化底蕴深厚的古镇,也是茂名市著名的革命老区。鳌头镇文物古迹众多,现存文武帝庙、观音阁、多善堂、古井、古衙门、东南古城门、四大当铺等文物一大批。
鳌头水乡桃花岛
鳌头水乡桃花岛
桃花岛是鳌头镇风景如画的袂花江段上的一座江心小岛,桃花岛有着古老美丽的传说,而岛上有一件弥足珍贵的鳌头老区革命文物——“革命船”。据记载,在上世纪四十年代中后期,地下党为便于经常护送地下党领导和飞马武工队队员到江中桃花岛进行革命活动而造此船,此船还多次运送伤病员转移到桃花岛避敌,为革命事业立下大功。因此,该船被当地群众誉为“革命船”。随着“革命船”纪念碑的建成,桃花岛成了革命传统教育基地。
灵惠寺
灵惠寺为唐代古刹,始建于公元714年,毁于明清,是粤西地区历史悠久的寺庙,建成后是粤西地区最大的寺庙之一。六祖寺方丈大愿大和尚应广大信众祈请,于2004年承接重建灵惠寺。重建后的灵惠寺位于茂名市森林公园后侧,占地面积200多亩,于2010年1月1日举行全堂佛像开光,现已宝殿庄严,佛身成就,大雄宝殿、功德堂、钟楼、鼓楼、方丈楼、僧寮、客堂、斋堂、山门、居士楼等拔地而起,古色古香,盘龙绕柱,高大雄伟。
福德境
福德境是历代村民敬奉神灵祈福之圣地,坐落在古代瓦窑——广东省茂名市茂南区山阁镇瓦岭村内西南部古榕树旁。相传清朝茂名县南部有个曾氏聚居烧瓦为商的地方叫瓦窑岭(今瓦岭),当地生长了一棵榕树(今古榕树),在某日树底下出现了一块疑似三角形的石块(称神石),石前点燃着三支香,从此当地居民在此敬奉神灵,从此这里祈者福荫,拜者庇佑,丁财昌盛,人才辈出,老少康宁。于是当地居民集资在古榕树旁修建了福德境庙,并将神石接入庙内敬奉。