源:http://blog.csdn.net/justfwd/article/details/45219895

 这篇文章纯粹属于安全分析研究,请勿用于非法用途。如有侵犯到厂家,请告知作者删除

12306Android客户端每个请求包都会带个baseDTO.check_code(如下图)作为数据包安全及完整性校验码,这个校验码由libcheckcode.so生成

   如果需要模拟购买火车票的过程,就要调用这个libcheckcode.so,不过这个SO使用dlopen无法加载。其ELF头,如下图所示,红框内表示ProgramHeader,里面的内容不符合elf格式规范

那它是如何加载起来的呢,猜测是借助了其它SO做了解密,下图列出lib/armeabi里的SO

分析后确定解密的工作是由libDexHelper.so来做的。 libDexHelper.so是最先加载的so,application调用的时候就加载了这个SO

libDexHelper.so自身做了加壳,这个壳不用花心思去脱,等它加载起来后,整个SO DUMP出来,将内存文件对齐修正一下就可以用IDA分析了

libDexHelper.so带有JNI_OnLoad,它会调用一个JNI_ALIYUN_ONLOAD函数

从函数名字上看,这个安全方案应该是由阿里云来做的

JNI_ALIYUN_ONLOAD内会做如下HOOK动作

也就是HOOK了dlopen,dlsym,_read,_open,mmap2五个函数,当加载libcheckcode.so的时候,会调用这五个函数,调用流程如下:

先调用dlopen,这里网上借个dlopen的调用流程图

这里的load_library会先调用_open打开文件,然后调用_read,再然后调用mmap2,将文件映射到内存

mmap2的hook过滤函数,当发现是libcheckcode.so文件时,会进行解密。

实际的解密代码,F5后,发下图所示:

是不是比较乱,它把跳转和循环改成了while switch方式,让人看得很纠结,所有长一点的函数都是这个样子。

等mmap2全部调用完了,把libcheckcode.so的内存DUMP出来,header如下图所示

已经变得正常了,这个文件直接IDA分析是没有结果的,需要将header里的文件偏移改成内存偏移,因为mmap已经将文件内容按内存对齐方式来存放了。

做一下对齐的修复,这个SO就可以用dlopen正常调用了。那么是不是大功告成了呢,我们写个12306的demo来调用这个so.

按MobileTicket逆向出来的代码描一个下面的类:

发现调用会CRASH,CRASH的偏移地址是1438a4,用IDA看下这段代码,这个地址就是checkcode的首地址

为什么会这样?回想一下,dlopen完了,还会调用初始化函数init_proc,IDA看下导出函数,确实存在一个叫.init_proc的函数

可以确定这里的init_proc就是壳代码,它还会继续对so进行解密,解密完了,这里才会有代码。

但是解密完了,这里运行仍然会出错。

什么原因呢?还有一个dlsym的HOOK函数没看

这个代码看得还是挺纠结的,就从它的return值往前推吧,基本可以确定它会返回wrapHook返回的内存地址。那就HOOK wrapHook,看它返回什么内容。

把wrapHook返回的内存块DUMP出来,用IDA分析

图上已经对这段代码做了标注。分析过程比较啰嗦,这里直接讲下结果吧。

dlsym的HOOK函数 功能:

如果要获取的函数名是Java_com_MobileTicket_CheckCodeUtil_checkcode,就调用wrapHook函数,返回wrapHook的返回值做为这个函数的地址。

wrapHook返回的代码段对Java_com_MobileTicket_CheckCodeUtil_checkcode函数重新做了一下包装,先调用so_prefix_wrap对Java_com_MobileTicket_CheckCodeUtil_checkcode函数进行解密,然后调用真实函数,调用完了再用so_postfix_wrap加密回去。

这里还有个细节要注意一下,这里的真实函数地址0x7bad6865是865结尾的,而我们的Java_com_MobileTicket_CheckCodeUtil_checkcode导出函数是以8a4结尾的,除了表示指令集不一样以外,同时指向的地址也是不一样的。

整理一下这个libcheckcode.so的加密方式,解密出来需要经过三个过程,先是mmap2解密,然后init_proc脱壳解密,最后调用checkcode函数的时候,还要运行时解密。

也就是说壳代码运行完后,checkcode还是处于加密状态,要使得libcheckcode.so能正常运行,init_proc之后还需要一次执行机会

怎么提供这个执行机会呢,想到两个办法,一个是patch  init_proc函数,使其执行完后再执行一段解密代码,还有一个办法是增加init_array

上图是dlopen里的一个代码片断,可以看到,init_func执行完后,还会再执行init_array指向的函数阵列。

patch代码不太好玩,这里选择增加init_array的办法

从下图可以看到,这个SO本身存在一个大小4的init_array,可以放一个函数地址

但是指向的地址是0

只要在164dd8放一个地址就可以了。

不过还有个问题,init_array指向的函数地址阵列是需要重定向的,还需要在重定向表里,把这个地址给加上

查看重定向表,发现重定向表的后面已经填上了其它结构的数据,并无空间来扩展。

那就只有整体搬家了。

这是dynamicsection解析到的重定位表的偏移0x1dc4和大小0x130

将这里的0x1dc4改成其它偏移,就可以对它进行搬家了,大小可根据需要扩大

要搬到哪里去呢,armelf文件的结构比较紧凑,难以在原有文件上找到空间,只有另外扩充空间了

从上图可以看到,第2个programtable只是用来指示dynamic section,第1个program table占据文件的后半部分,只要把扩充的内容放到文件末尾,然后相应增加FileSize和MemSize两个就可以

扩充完了,把重定位表搬过去,并增加四字节大小

重定位表搬完了,init_array里的函数地址指向哪里呢。这个函数用来对checkcode函数进行解密。

要怎么去解密呢,逆向算法成本比较高,就直接把so_prefix_wrap运行后解出来的内存直接copy到原位置好了。把要拷贝的源和拷贝函数都放到第1节扩充的空间里去。

用C语言写个拷贝内存的代码,编译后,把那段拷贝函数,填到init_array函数指向的地址,再做一些必要的修改,让它可以正常运行。

最后一步把第1节的Flag加上可执行属性,改成跟第0节一样,都为RWX就行了。

至此,libcheckcode.so可以单独运行,不再需要借助libDexHelper.so的解密。

12306 Android客户端的libcheckcode.so解密及修复的更多相关文章

  1. android 客户端 RSA加密 要注意的问题

    针对java后端进行的RSA加密,android客户端进行解密,结果是部分乱码的问题:注意两点,编码问题和客户端使用的算法问题 即:都使用UTF-8编码,Base64使用一致,另外,使用下面的代码在后 ...

  2. Android 客户端 okhttp3 与服务器之间的双向验证

    [原文]https://blog.csdn.net/leng_wen_rou/article/details/58596142 本篇是Android 客户端基于okhttp3的网络框架 和后台服务器之 ...

  3. [PHP]AES加密----PHP服务端和Android客户端

    本文采取128位AES-CBC模式加密和解密 1.首先对服务端安装mcrypt: sudo apt-get install php5-mcrypt php5-dev sudo php5enmod mc ...

  4. Android客户端和服务器端数据交互

    网上有很多例子来演示Android客户端和服务器端数据如何实现交互不过这些例子大多比较繁杂,对于初学者来说这是不利的,现在介绍几种代码简单.逻辑清晰的交互例子,本篇博客介绍第四种: 一.服务器端: 代 ...

  5. appium 自动化测试之知乎Android客户端

    appium是一个开源框架,相对来说还不算很稳定.转载请注明出处!!!! 前些日子,配置好了appium测试环境,至于环境怎么搭建,参考:http://www.cnblogs.com/tobecraz ...

  6. 仿优酷Android客户端图片左右滑动(自动滑动)

    最终效果: 页面布局main.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayou ...

  7. 【原创】轻量级即时通讯技术MobileIMSDK:Android客户端开发指南

    申明:MobileIMSDK 目前为个人维护的原创开源工程,现陆续整理了一些资料,希望对需要的人有用.如需与作者交流,见文章底签名处,互相学习. MobileIMSDK开源工程的代码托管地址请进入 G ...

  8. 基于SuperSocket的IIS主动推送消息给android客户端

    在上一篇文章<基于mina框架的GPS设备与服务器之间的交互>中,提到之前一直使用superwebsocket框架做为IIS和APP通信的媒介,经常出现无法通信的问题,必须一天几次的手动回 ...

  9. Android客户端性能优化(魅族资深工程师毫无保留奉献)

    本文由魅族科技有限公司资深Android开发工程师degao(嵌入式企鹅圈原创团队成员)撰写,是degao在嵌入式企鹅圈发表的第一篇原创文章,毫无保留地总结分享其在领导魅族多个项目开发中的Androi ...

随机推荐

  1. HttpComponents 也就是以前的httpclient项目

    HttpComponents 也就是以前的httpclient项目,可以用来提供高效的.最新的.功能丰富的支持 HTTP 协议的客户端/服务器编程工具包,并且它支持 HTTP 协议最新的版本和建议.不 ...

  2. zzuli Camellia的难题(暴力)

    1784: Camellia的难题 Time Limit: 2 Sec  Memory Limit: 128 MB Submit: 67  Solved: 14SubmitStatusWeb Boar ...

  3. erlang 初体验

    近期測试了一下 erlang的坑... 如不出意外.... 大家第一眼看到这语法... 心里第一句一定是"我擦.这TM都是啥!!!!!" 没有变量!!! 没有结构体!!! 没有循环 ...

  4. stm32之watchdog

    在嵌入式系统中,由于MCU的工作常常受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统陷入停滞状态,发送不可预料的后果,所以出 ...

  5. 解析stm32的时钟

    STM32 时钟系统  http://blog.chinaunix.net/uid-24219701-id-4081961.html STM32的时钟系统 ***   http://www.cnblo ...

  6. BZOJ 2038: [2009国家集训队]小Z的袜子(hose) ( 莫队 )

    莫队..先按sqrt(n)分块, 然后按块的顺序对询问排序, 同块就按右端点排序. 然后就按排序后的顺序暴力求解即可. 时间复杂度O(n1.5) --------------------------- ...

  7. BZOJ 1537: [POI2005]Aut- The Bus(dp + BIT)

    对y坐标离散化, 然后按x坐标排序, dp. 一个点(x, y), 设到达这个点接到的最多乘客数为t, 那么t可以用来更新y'>=y的所有点.用树状数组维护最大值. -------------- ...

  8. 【代码】Android: 怎样设置app不被系统k掉

    有一种方法可以设置app永远不会被kill,AndroidManifest.xml 中添加: android:persistent="true" 适用于放在/system/app下 ...

  9. iOS- 如何集成支付宝

    链接地址:http://www.cnblogs.com/qingche/p/3556365.html 现在不少app内都集成了支付宝功能   使用支付宝进行一个完整的支付功能,大致有以下步骤: 1&g ...

  10. 将258.369 double值转为内存表示(科学计数法)

    前言 庖丁解牛 - <<庄子>> 庖丁为文惠君解牛,手之所触, 肩之所倚, 足之所履, 膝之所踦, 砉然向然, 奏刀騞然, 莫不中音, 合于<桑林>之舞, 乃中&l ...