一、前言

   前两篇文章链接:

    1、DEX文件头解析

    2、DEX文件校验和解析

   PS:前几天检查文件夹的时候发现DEX文件解析还只写了开头,正好找点事情来做,就去接着解析DEX文件其余部分了。。。。。(还得多亏了一波疫情,不然都忘了还有这回事了。。。)


二、DEX文件中的字符串

    1、DEX文件大致上可以粗略的分为3个部分:文件头、索引区以及数据区。而文件头一般来说占了整个DEX文件0x70个字节(还不了解DEX文件头的可以看一下我前面两篇文章),在文件头中,关于字符串的相关信息一共有8个字节,分别位于0x38(4 Bytes)和0x3c(4 Bytes)处,前者说明了该DEX文件包含了多少个字符串,后者则是字符串索引区的起始地址,但是需要注意的是,DEX存储是以小端序存储的(通俗一点的说就是从后往前读),如下所示:

    2、前面我们通过文件头知道了字符串数量和字符串索引区起始地址等信息,接下来我们就来具体看一下字符串索引区。字符串索引区存储的是字符串真正存储在数据区的偏移地址,以4个字节为一组,表示一个字符串在数据区的偏移地址,所以索引区一个占字符串数量 X 4个字节那么多,同样的,索引区也采用的是小端序存储,所以我们在读取地址时,需要与小端序的方式来读取真正的地址,如下所示:

    3、从上面我们已经知道了如何找到字符串在数据区的偏移地址,接下来我们需要做的就是解析这些数据区的字节。通过偏移地址我们可以在数据区找到代表字符串的这些字节,在DEX文件中,字符串是通过MUTF-8编码而成的(至于mutf-8是什么编码,我会将一些相关博客链接贴在文末),在MUTF-8编码中,第一个字节代表了这个字符串所需要用到的字节数目(不包括最后一个代表终结的字节),最后一个字节为0x00,表示这个字符串到此结束,跟c语言有点类似,中间部分才是一个字符串的具体内容,如下所示:(PS:mutf-8第一个字节还经过uleb128编码,所以简单的进行进制换算得到的字节数很多人奇怪对不上,由于比较复杂,就不过多解释了,想进一步了解更深的可以去看一下安卓源码中对DEX文件解析出字符串这一部分)


三、解析代码:

    PS:我电脑运行环境--python3.6

代码如下:

import binascii
import os
import sys def getStringsCount(f):
f.seek(0x38)
stringsId = f.read(4)
a = bytearray(stringsId)
a.reverse()
stringsId = bytes(a)
stringsId = str(binascii.b2a_hex(stringsId),encoding='UTF-8')
count = int(stringsId,16)
print('[+] stringSize ==> ' + str(count))
return count def getStringByteArr(f,addr):
byteArr = bytearray()
f.seek(addr + 1)
b = f.read(1)
b = str(binascii.b2a_hex(b),encoding='UTF-8')
b = int(b,16)
index = 2
while b != 0:
byteArr.append(b)
f.seek(addr + index)
b = f.read(1)
b = str(binascii.b2a_hex(b),encoding='UTF-8')
b = int(b,16)
index = index + 1
return byteArr def BytesToString(byteArr):
try:
bs = bytes(byteArr)
stringItem = str(bs,encoding='UTF-8')
print('[*] str = ' + stringItem)
return stringItem
except:
pass def getAddress(addr):
address = bytearray(addr)
address.reverse()
address = bytes(address)
address = str(binascii.b2a_hex(address),encoding='UTF-8')
address = int(address,16)
return address def getStrings(f,stringAmount):
stringsList = []
f.seek(0x3c)
stringOff = f.read(4)
Off = getAddress(stringOff)
f.seek(Off)
for i in range(stringAmount):
addr = f.read(4)
address = getAddress(addr)
byteArr = getStringByteArr(f,address)
stringItem = BytesToString(byteArr)
stringsList.append(stringItem)
Off = Off + 4
f.seek(Off) if __name__ == '__main__':
filename = str(os.path.join(sys.path[0])) + '\\1.dex'
f = open(filename,'rb',True)
stringsCount = getStringsCount(f)
getStrings(f,stringsCount)
f.close()

运行截图:


四、一些总结

    其实也没有什么好总结的,因为本身这没有什么难点之处,就记录一些遇见的问题吧!!!最开始解析字符串的时候发现MUTF-8编码的时候好不容易弄懂了的时候,发现还经过uleb128,所以最开始一直没办法通过第一个字节计算出需要编码的字节个数,最后取了个巧,从第二个字节开始读取知道读取到0x00为止;然后是怎么编码这些字节显示字符串,后来看了一下姜维大佬写的解析代码,发现直接用的是utf-8进行编码,转念一想,mutf-8也是utf-8的变种,所以大部分解析出来基本没有问题。写完代码后本来打算去看一下安卓源码是怎么解析这一块的再来模仿一下,但是这疫情让我已经耍了这么久了,实在没精神去看了,我还是接着去微博上蹲在@四川教育吧,看源码什么的还是开学了再说吧!!!


五、一下链接和附件

  1、相关知识链接:

    MUTF-8编码:https://blog.csdn.net/Roland_Sun/article/details/46716965

    uleb128:https://blog.csdn.net/Roland_Sun/article/details/46708061

  2、样本及代码下载链接:

    百度网盘链接:https://pan.baidu.com/s/1_CQP7Zrj9LHcLOIjdGD95A;提取码:yc9y

DEX文件解析--3、dex文件字符串解析的更多相关文章

  1. plist文件、NSUserDefault 对文件进行存储的类、json格式解析

    ========================== 文件操作 ========================== Δ一 .plist文件 .plist文件是一个属性字典数组的一个文件: .plis ...

  2. XML文件解析并利用SimpleAdapter将解析结果显示在Activity中

    首先创建一个实体类 Mp3Info用来存储解析的XML文件中的内容: public class Mp3Info implements Serializable{ private static fina ...

  3. C语言解析Ini格式文件

    引用别人的博文: http://www.open-open.com/lib/view/open1402278076447.html 可以解析 INI 格式的字符串.解析文件.保存到文件. 下面是头文件 ...

  4. Java使用正则表达式解析LRC歌词文件

    LRC歌词是一种应用广泛的歌词文件,各主流播放器都支持. lrc歌词文本中含有两类标签: 1.标识标签(ID-tags) [ar:艺人名] [ti:曲名] [al:专辑名] [by:编者(指编辑LRC ...

  5. 全面解析Linux数字文件权限

    全面解析Linux数字文件权限 来源:   时间:2013-09-04 20:35:13   阅读数:11433 分享到:0 [导读] 在刚开始接触Linux时对于文件权限的理解并不是很透彻,这里详细 ...

  6. JavaWeb实现文件上传下载功能实例解析

    转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web应用系统开发中,文件上传和下载功能是非常常用的功能 ...

  7. boost.spirit之解析C++头文件

    环境:win7_64旗舰版,VS2008 场景:C++与lua交互是比较繁琐的,当我们编写一个C++类后,如果要给lua使用,就必须写一个lua包装类,将lua与原始C++类关联起来.其实这部分代码编 ...

  8. POI使用:解析xls/xlsx文件(兼容office2003/2007/2010版本)

    package cn.eguid; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; imp ...

  9. C语言解析WAV音频文件

    C语言解析WAV音频文件 代码地址: Github : https://github.com/CasterWx/c-wave-master 目录 前言 了解WAV音频文件 什么是二进制文件 WAV的二 ...

随机推荐

  1. mermaid使用简介(画论文插图的一种解决方案)

    官方IO: https://mermaid-js.github.io/mermaid/#/ 官方对mermaid的简介是这样的:Markdownish syntax for generating fl ...

  2. Laravel模板引擎Blade中section的一些标签的区别介绍

    Laravel 框架中的 Blade 模板引擎,很好用,但是在官方文档中有关 Blade 的介绍并不详细,有些东西没有写出来,而有些则是没有说清楚.比如,使用中可能会遇到这样的问题: 1.@yield ...

  3. linux下操作memcache的操作命令

    1.连接memcache linux下一般使用telnet连接memcache服务 [root@localhost ~]# telnet 127.0.0.1 11266 Trying 127.0.0. ...

  4. Linux下搭建redis(源码编译)

    [准备环境] Linux centos7 redis下载包  地址:http://www.redis.cn/download.html  前往下载稳定版本 [步骤] 1.下载成功后 把包上传到服务器 ...

  5. Charles 功能详解

    Charles的功能有? 1 抓取http和https 网络封包(抓包) 2 Charles 的断点请求 通过断点修改参数 在指定接口打上断点 右键点击接口选择 breakpoints 然后 导航栏 ...

  6. 【DP-动态代理】JDK&Cglib

    需求:增强未知方法的代码 简单方案:继承或者聚合 继承,调用方法前后加增强逻辑 聚合 - 静态代理 持有被代理类对象 或者接口 可通过嵌套实现代理的组合 和 装饰器模式很像 高级方案 代理所有的类,不 ...

  7. Spring:一、基本模块思维导图

  8. Python3-apscheduler模块-定时调度

    from apscheduler.schedulers.background import BackgroundScheduler, BlockingScheduler from apschedule ...

  9. web开发相关概念

    什么是web通信? WEB采用B/S通信模式,通过超文本传送协议(HTTP, Hypertext transport protocol)进行通信.通过浏览器地址栏编写URL,向服务器发送一个请求,服务 ...

  10. conda+豆瓣源配置tensorflow+keras环境

    conda+豆瓣源配置tensorflow+keras环境 安装anaconda 打开Anaconda Prompt 创建虚拟环境 conda create -n myenv python=3.5 a ...