DEX文件解析--3、dex文件字符串解析
一、前言
前两篇文章链接:
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文件字符串解析的更多相关文章
- plist文件、NSUserDefault 对文件进行存储的类、json格式解析
========================== 文件操作 ========================== Δ一 .plist文件 .plist文件是一个属性字典数组的一个文件: .plis ...
- XML文件解析并利用SimpleAdapter将解析结果显示在Activity中
首先创建一个实体类 Mp3Info用来存储解析的XML文件中的内容: public class Mp3Info implements Serializable{ private static fina ...
- C语言解析Ini格式文件
引用别人的博文: http://www.open-open.com/lib/view/open1402278076447.html 可以解析 INI 格式的字符串.解析文件.保存到文件. 下面是头文件 ...
- Java使用正则表达式解析LRC歌词文件
LRC歌词是一种应用广泛的歌词文件,各主流播放器都支持. lrc歌词文本中含有两类标签: 1.标识标签(ID-tags) [ar:艺人名] [ti:曲名] [al:专辑名] [by:编者(指编辑LRC ...
- 全面解析Linux数字文件权限
全面解析Linux数字文件权限 来源: 时间:2013-09-04 20:35:13 阅读数:11433 分享到:0 [导读] 在刚开始接触Linux时对于文件权限的理解并不是很透彻,这里详细 ...
- JavaWeb实现文件上传下载功能实例解析
转:http://www.cnblogs.com/xdp-gacl/p/4200090.html JavaWeb实现文件上传下载功能实例解析 在Web应用系统开发中,文件上传和下载功能是非常常用的功能 ...
- boost.spirit之解析C++头文件
环境:win7_64旗舰版,VS2008 场景:C++与lua交互是比较繁琐的,当我们编写一个C++类后,如果要给lua使用,就必须写一个lua包装类,将lua与原始C++类关联起来.其实这部分代码编 ...
- POI使用:解析xls/xlsx文件(兼容office2003/2007/2010版本)
package cn.eguid; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; imp ...
- C语言解析WAV音频文件
C语言解析WAV音频文件 代码地址: Github : https://github.com/CasterWx/c-wave-master 目录 前言 了解WAV音频文件 什么是二进制文件 WAV的二 ...
随机推荐
- java中Proxy类初探
在java中提供了一个动态代理类,这个类位于java.lang.reflect包中的Proxy类中.什么是动态代理类呢?就是可以在运行时创建一个实现了一组给定接口的新类.听上去有点高深的样子,其实是提 ...
- Jenkins项目构建运行
[准备环境] 继Jenkins环境搭建完成后,进行插件的管理 [思路] 项目顺序是,开发提交代码到代码仓库,测试通过Jenkins拉下开发的代码打包部署: 1.开发提交代码 2.Jenkins自动从代 ...
- Linux常用命令之文件磁盘管理
前言 本文知识点是曾经学习过程中收录整理的,方便学习使用. 一>Linux常用基本命令 Linux命令格式:command [-options] [parameter1] ... command ...
- 大文件上传、断点续传、秒传、beego、vue
大文件上传 0.项目源码地址 源码地址 :https://github.com/zhuchangwu/large-file-upload 它是个demo,仅供参考 前端基于 vue-simple-up ...
- 尚学堂 208.Annotation注解和内置注解
208.Annotation注解和内置注解 override:这个注释的作用是标识某一个方法是否覆盖了它的父类的方法deprecated:表示果某个类成员的提示中出现了个词,就表示这个并不建议使用这个 ...
- Redhat FreeIPA Server 安装服务端和客户端 (实验:VMware环境下)
实验环境:windows7 + vmware 15 + redhat 71:准备2台虚拟机: 虚拟机VMnet8,Subnet IP:192.168.145.0 Redhat 7( ...
- JDK8--02:为什么要使用lambda
lambda是一个匿名函数,我们可以把lambda理解为一个可以传递的代码(将代码像数据一样传递),可以写出更简洁更灵活的代码.首先看一下原来的匿名内部类实现方式(以比较器为例) //原来的匿名内部类 ...
- SpringBoot中VO,DTO,DO,PO的概念、区别和用处
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/zhuguang10/article/de ...
- Python3笔记016 - 4.1 序列
第4章 序列的应用 python的数据类型分为:空类型.布尔类型.数字类型.字节类型.字符串类型.元组类型.列表类型.字典类型.集合类型 在python中序列是一块用于存放多个值的连续内存空间. py ...
- 《MapReduce: Simplified Data Processing on Large Clusters》论文研读
MapReduce 论文研读 说明:本文为论文 <MapReduce: Simplified Data Processing on Large Clusters> 的个人理解,难免有理解不 ...