密码学在Android加密中的应用和实践——MD5(1)

上一节课我们介绍说——加解密是App逆向分析,Js逆向中都十分重要和不可或缺的一部分,所以我们有必要从一个整体的、俯视的角度去了解Android中的加解密算法。这节课我们来具体的验证和学习它。我们讲解的第一个加解密算法是MD5算法。

一.什么是MD5

MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。

上面这是比较正式和官方的解释,我们使用更加通俗、实用、具体的语言来描述它。

  1. MD5是一种散列函数,散列函数又译做哈希函数(Hash),很多人习惯称之为MD5加密算法,但实际上MD5是一种散列算法

  2. 加密算法分为单向加密和双向加密,MD5是单向加密,比如123456的MD5值是e10adc3949ba59abbe56e057f20f883e,在理论上,没有办法可以从MD5值e10adc3949ba59abbe56e057f20f883e倒推到123456。而在双向加密算法中,加密的结果可以使用密钥和算法将加密以后的密文解密为原文,而MD5不行。MD5是单向加密这一点很关键,我们后续会再提到它。

  3. 对源数据进行最小的改变,MD5的结果变动都会非常大,值会完全不同。与此同时,只要明文不变,无论计算多少遍,MD5值都完全相同。而有一些加密算法,明文相同,加密结果可能有许多种。

  4. MD5在Android中常用来用作sign签名:比如账号注册/登录时,计算密码的MD5值,传输时使用密码的MD5值;比如POST data中,常常就是对其他所有POST的字段进行拼接,之后求MD5值,只要你一个字段值不对,这个md5值就不可能正确,这样就很好的达到了防护和验证的目的。这个签名字段有时候叫sign,也有时候直接用原意signature(签名)。

5. 任意长度的数据得到的MD5值长度是固定的,总是由16进制组成的32位字符串,即只包含数字0到9和字母A到F(或a~f)。


下面是几个JS和Android中的例子

  • 微信公众平台的密码提交

密码学在Android加密中的应用和实践——MD5(1)_第1张图片

  • 某不知名app中用MD5对post data进行加密(apisign字段)

密码学在Android加密中的应用和实践——MD5(1)_第2张图片

  • 新浪Android客户端用MD5进行签名验证(sign字段)

密码学在Android加密中的应用和实践——MD5(1)_第3张图片

  • 小红书app中的Post字段,sign显然是MD5,除此之外,deviceId也像是一个MD5,在固定的间隔加上-分隔符而已,device-finger(即设备指纹)似乎由几个内容拼凑而成,其中似乎也有一部分是MD5。

密码学在Android加密中的应用和实践——MD5(1)_第4张图片

上面我们讲了什么是MD5,那么我们为什么需要了解MD5????

    从上文我们可以知道MD5最明显的两个特征是32位和不可逆

	如何利用这两个特征?

我们就可以在抓包和JS解密时,一看到32位的字符串,且只有0-9+a-f这十六个字符出现,就立马意识到这是一个MD5,然后针对MD5加密的特征进行突破,而不是毫无底气的乱找

属于何种加密这个信息本身,就可以提供大量的信息。

比如在Android开发中中,MD5加密的实现代码往往是类似的,所以我们可以针对其中必须要使用的方法、函数和流程,进行Hook(后续会讲),这样就可以得到程序中加密前的原文和堆栈调用。

而在Js解密中,如果我们确定某个参数是MD5加密,但我们始终找不到这个参数生成的具体逻辑,那么我们也可以直接全局搜索MD5函数,直接在实现MD5的Javascript函数上打断点。

我们先来想一下服务器的美梦,将许多个字段拼接join在一起,然后轻轻松松求个MD5,根据我们上面讲的第三点,MD5原文只要发生微小变化,MD5的结果就会完全不同。

那么如果请求字段中加上sign,当你想通过爬虫程序大规模模拟请求数据时,只要有一个字段没搞清楚,或者一个字段没有解密出来,sign的MD5就必定是错的,服务器验证不通过,资源不予请求,多么爽歪歪。

但是

MD5是不可逆的,那么我们就需要考虑——服务器它自己拿到了MD5值,却也没办法还原成原文,来查看和比对每个字段的内容,那怎么验证你提交的字段是对是错??
密码学在Android加密中的应用和实践——MD5(1)_第5张图片
所以呀,服务器没办法逆向MD5的结果,它只好拿一模一样的原数据做一遍MD5,校验结果。

那么首先,它需要将源数据和签名后的值一起提交到后台,保证服务器拥有原数据。比如通过一个很长的get请求,里面一堆杂七杂八的字段,加上一个sign字段,或者通过一个简单的post data。

其次,这里有一个问题,我们前面说,sign可能是对六七八九十个字段先进行拼接,然后进行MD5加密,得到一个结果,那么假设我们的字段如下?

“c=3&f=lilac&a=verison 3.3&d=timestamp&……&g=……&……”

怎么确定字段拼接的先后呢?

你把一堆东西塞进某个Java集合,万一集合自己对数据进行了个啥排序,或者某个字段用户没提交/不需要提交时,那不就全乱套了吗?怎么保证你在本地的加密顺序和服务器端加密顺序是一致的呢?
密码学在Android加密中的应用和实践——MD5(1)_第6张图片

在Android开发中,通常使用的处理办法是先对字段进行排序。

比如说,把需要参与MD5加密的字段的字段名,单独拎出来搞个数组,弄一下array.sort排序,然后再通过字典取值的方式拼接出排序后的key value值进行MD5.

处理前:“c=3&f=lilac&a=verison 3.3&b=timestamp&……&g=……&……”
处理后:“a=version3.3&b=timestamp&c=3&……”

正因为在Android的客户端和服务器中都做了这样的处理,因此排序不会出现问题了。

那么当我们反编译源码时,几千几万行代码中,就需要有意识的看这样的代码结构,一眼看到一个map集合,下面对它进行了sort排序,稳了稳了,十有八九是你要找的MD5.

到此为止吧,这一篇blog。
密码学在Android加密中的应用和实践——MD5(1)_第7张图片
现在是凌晨一点半,blog是从10点开始写的,我现在关心这样几件事:

  1. 我的blog系列主线是Android逆向入门,密码学xxx这个系列是Androdi逆向中打怪升级必要的副本,那么……我每个blog的内容有什么问题吗,够细致吗?可以让新手去理解和不恐惧逆向吗?深度需要提升吗?排版有问题吗?有什么我没注意到的地方吗?
  2. 有人在看我的blog吗?它……有意义吗?
  3. 写blog真的很耗费时间,尤其我爱追求尽善尽美,这给我带来了很多时间上的耗费。网上已经有太多太多Android逆向的视频教程、博客教程了。但我着实感觉它们的起点和基础太高,很多都是面向Java高级程序员和Android开发人员,因此开局就arm汇编,就是JNI,而许多希望通过app逆向实现爬虫程序的Python程序员,开局……甚至没有一条狗,基础相差太多,Android逆向书籍即使拿到手也只能空叹气。其次,一些大佬或者语言如梦呓和饶舌让人费解,或者留一手留的太多,只给结果留人瞻仰,不留思考和步骤供人学习,真的很让人遗憾,因此才萌生了自己写一个系列的尝试和想法。
  4. 我可爱的小女朋友现在在做什么梦呢?是一个芒果味的悠哈软糖梦?还是一条虎鲸或者一只大白狗?我现在很想她,但为了未来我们还要忍受很久的异地和寂寞。

参考和借鉴的BLOG
https://blog.csdn.net/qq_30993595/article/details/80453807
https://blog.csdn.net/baidu_34045013/article/details/80687557

接下来几个小节的内容才是实践和重点,大家加油!

二.Java实现MD5加密与Andoid实例

三.让加密更加安全——MD5的一些小变体

你可能感兴趣的:(密码学在Android加密中的应用和实践——MD5(1))