DEX文件解析--5、dex方法原型解析
一、前言
前几篇文章链接:
DEX文件解析---1、dex文件头解析
DEX文件解析---2、Dex文件checksum(校验和)解析
DEX文件解析--3、dex文件字符串解析
DEX文件解析--4、dex类的类型解析
二、DEX文件中的方法原型
1、关于dex文件中方法原型的解析,需要知道怎么解析出字符串和类的类型,不明白的可以看我前几篇的解析。DEX文件中的方法原型定义了一个方法的返回值类型和参数类型,例如一个方法返回值为void,参数类型为int,那么在dex文件中该方法原型表示为V(I)(smali中V表示void,I表示int)。在dex文件头部中,关于方法原型有两处,第一处位于0x48处,用4个字节定义了方法原型的数量,在0x4C处用4个字节定义了方法原型的偏移地址,如下所示:

2、在上面我们知道了方法原型的起始偏移地址,接下来我们根据这个偏移地址找到方法原型,同样的,跟解析类的类型比较类似,一个方法原型所占字节数为12个字节,第一个字节到第四个字节表示了定义方法原型的字符串,这四个字节按小端序存储,读取出来为在字符串列表的索引,例如一个方法原型返回值为void,参数为boolean,那么定义该方法原型的字符串即为VZ;第5个字节到第八个字节表示该方法原型的返回值类型,读取出来的值为前面解析出来的类的类型列表的索引;第8个字节到第十二给字节表示该方法原型的参数,读取出来为一组地址,通过该地址可以找到该方法原型的参数,跳转到该地址去,首先看前4个字节,前四个字节按照小端序存储,读取出来的值为该方法原型参数的个数,接着根据参数个数,读取具体的参数类型,每个参数类型占2个字节,这两个字节读取出来的值为前面解析出来的类的类型列表的索引,如下所示:


三、解析代码
运行环境:我电脑环境为python3.6
运行截图:


解析代码:
import binascii
import os
import sys
def byte2int(bs):
tmp = bytearray(bs)
tmp.reverse()
rl = bytes(tmp)
rl = str(binascii.b2a_hex(rl),encoding='UTF-8')
rl = int(rl,16)
return rl
def getStringsCount(f):
f.seek(0x38)
stringsId = f.read(4)
count = byte2int(stringsId)
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')
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)
return stringsList
def getTypeAmount(f):
f.seek(0x40)
stringsId = f.read(4)
count = byte2int(stringsId)
return count
def getTypeItem(f,count,strLists):
typeList = []
f.seek(0x44)
type_ids_off = f.read(4)
type_off = byte2int(type_ids_off)
f.seek(type_off)
for i in range(count):
typeIndex = f.read(4)
typeIndex = byte2int(typeIndex)
typeList.append(strLists[typeIndex])
type_off = type_off + 0x04
f.seek(type_off)
return typeList
def changeDisplay(viewString):
display = ''
if viewString == 'V':
display = 'void'
elif viewString == 'Z':
display = 'boolean'
elif viewString == 'B':
display = 'byte'
elif viewString == 'S':
display = 'short'
elif viewString == 'C':
display = 'char'
elif viewString == 'I':
display = 'int'
elif viewString == 'J':
display = 'long'
elif viewString == 'F':
display = 'float'
elif viewString == 'D':
display = 'double'
elif viewString[0:1] == 'L':
display = viewString[1:-1]
elif viewString[0:1] == '[':
if viewString[1:2] == 'L':
display = viewString[2:-1] + '[]'
else:
if viewString[1:] == 'Z':
display = 'boolean[]'
elif viewString[1:] == 'B':
display = 'byte[]'
elif viewString[1:] == 'S':
display = 'short[]'
elif viewString[1:] == 'C':
display = 'char[]'
elif viewString[1:] == 'I':
display = 'int[]'
elif viewString[1:] == 'J':
display = 'long[]'
elif viewString[1:] == 'F':
display = 'float[]'
elif viewString[1:] == 'D':
display = 'double[]'
else:
display = ''
else:
display = ''
return display
def parseProtold(f,typeList,stringList):
f.seek(0x48)
protoldSizeTmp = f.read(4)
protoldSize = byte2int(protoldSizeTmp)
print('[+] protold size ==> ',end='')
print(protoldSize)
f.seek(0x4c)
protoldAddr = byte2int(f.read(4))
for i in range(protoldSize):
f.seek(protoldAddr)
AllString = stringList[byte2int(f.read(4))]
protoldAddr += 4
f.seek(protoldAddr)
returnString = typeList[byte2int(f.read(4))]
protoldAddr += 4
f.seek(protoldAddr)
paramAddr = byte2int(f.read(4))
if paramAddr == 0:
protoldAddr += 4
print(f'[-] protold[{i}] ==> ',end='')
print(AllString + ' : ',end='')
print(changeDisplay(returnString) + '()')
continue
f.seek(paramAddr)
paramSize = byte2int(f.read(4))
paramList = []
if paramSize == 0:
pass
else:
paramAddr = paramAddr + 4
for k in range(paramSize):
f.seek(paramAddr + (k * 2))
paramString = typeList[byte2int(f.read(2))]
paramList.append(paramString)
protoldAddr += 4
paramTmp = []
for paramItem in paramList:
paramTmp.append(changeDisplay(paramItem))
print(f'[-] protold[{i}] ==> ',end='')
print(AllString + ' : ',end='')
print(changeDisplay(returnString) + '(',end='')
param = ','.join(paramTmp)
print(param + ')')
if __name__ == '__main__':
filename = str(os.path.join(sys.path[0])) + '\\1.dex'
f = open(filename,'rb',True)
stringsCount = getStringsCount(f)
strList = getStrings(f,stringsCount)
typeCount = getTypeAmount(f)
typeList = getTypeItem(f,typeCount,strList)
parseProtold(f,typeList,strList)
f.close()
四、相关链接以及样本代码下载加总结
1、总结:没啥可以总结的,就是代码写的比较丑,大佬勿喷!!!
2、smali数据格式参考链接:https://blog.csdn.net/ls0111/article/details/76228068
3、样本及代码下载链接:
百度网盘:https://pan.baidu.com/s/1dF-V7oSoXv_shYw7GlP84A,提取码:wzdu
DEX文件解析--5、dex方法原型解析的更多相关文章
- APK程序Dex文件无源码调试方法讨论
那些不靠谱的工具 先来说说那些不靠谱的工具,就是今天吭了我小半天的各种工具,看官上坐,待我细细道来.IDA pro IDA pro6.6之后加入了dex动态调试功能,一时间普天同庆.喜大普奔.兴奋之后 ...
- 遍历文件 创建XML对象 方法 python解析XML文件 提取坐标计存入文件
XML文件??? xml即可扩展标记语言,它可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言. 里面的标签都是可以随心所欲的按照他的命名规则来定义的,文件名为roi.xm ...
- DEX文件解析--6、dex文件字段和方法定义解析
一.前言 前几篇文章链接: DEX文件解析---1.dex文件头解析 DEX文件解析---2.Dex文件checksum(校验和)解析 DEX文件解析--3. ...
- DEX文件解析--7、类及其类数据解析(完结篇)
一.前言 前置技能链接: DEX文件解析---1.dex文件头解析 DEX文件解析---2.Dex文件checksum(校验和)解析 DEX文件解析--3.d ...
- 插件化框架解读之Class文件与Dex文件的结构(一)
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 Class文件 Class文件是Java虚拟机定义并被其所识别的 ...
- DEX文件类型和虚拟机(摘抄)
DEX文件类型是Android平台上可执行文件的类型. Dalvik是Google公司自己设计用于Android平台的Java虚拟机.Dalvik虚拟机是Google等厂商合作开发的Android移动 ...
- TP框架ajax U方法不解析怎么办?
TP框架中ajax U方法不解析 ajax U方法不解析 ajax url不解析 问题: 造成问题原因: Js 存在单独的 js文件中和html分离了.造成不解析! 解决方法: 方法一:将js放到ht ...
- Dex文件方法数超过65536怎么破?
你的应用中的Dex 文件方法数超过了最大值65536的上限,会提示你: UNEXPECTED TOP-LEVEL EXCEPTION:java.lang.IllegalArgumentExceptio ...
- Android平台dalvik模式下java Hook框架ddi的分析(2)--dex文件的注入和调用
本文博客地址:http://blog.csdn.net/qq1084283172/article/details/77942585 前面的博客<Android平台dalvik模式下java Ho ...
随机推荐
- 解决mysql插入数据l出现"the table is full"的问题
需要修改Mysql的配置文件my.ini,在[mysqld]下添加/修改两行:tmp_table_size = 256Mmax_heap_table_size = 256M
- cc31a_demo--CppPrimer_静态成员与继承-在派生类中访问基类中的static成员的方法
//*基类中的static成员,在整个继承层次中只有一个实例 //*在派生类中访问基类中的static成员的方法 //1.基类名::成员名 //2.子类名::成员名 //3.对象.成员名 //4.指针 ...
- ASP.NET Core 对Controller进行单元测试
单元测试对我们的代码质量非常重要.很多同学都会对业务逻辑或者工具方法写测试用例,但是往往忽略了对Controller层写单元测试.我所在的公司没见过一个对Controller写过测试的.今天来演示下如 ...
- rest_framework django 简单使用(数据库创建数据, 覆盖数据, 其他的大同小异)
事先说几个坑:数据库定义字段时候,不要定义name 要定义 username 首先, 定义model(简单定义) from django.db import models from django.co ...
- TiDB初探
TiDB是一个开源的分布式NewSQL数据库,设计的目标是满足100%的OLTP和80%的OLAP,支持SQL.水平弹性扩展.分布式事务.跨数据中心数据强一致性保证.故障自恢复的高可用.海量数据高并发 ...
- 多语言工作者の十日冲刺<1/10>
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 团队进行Alpha冲刺--第一天(04.30) 作业正文 ...
- c#,pagerank算法实现一
PageRank让链接来"投票" 一个页面的“得票数”由所有链向它的页面的重要性来决定,到一个页面的超链接相当于对该页投一票.一个页面的PageRank是由所有链向它的页面(“链入 ...
- mongodb 数据库 增删改查
mongodb 数据库 增删改查 增: // 引入express 模块 var express = require('express'); // 路由var router = expr ...
- JSON Web令牌(JWT)介绍与使用
手机端接口开发会遇到一个问题是,接口登录后需要返回一个Token.token首先有一点必须唯一,每次请求都需要把token给带上.基于必须唯一的特性,很多朋友在开发是都选择了uuid.是不是token ...
- Docker(一)Docker概述
Docker概述 概述 Docker是供开发人员和系统管理员 使用容器构建,运行和共享应用程序的平台.使用容器来部署应用程序称为容器化.容器不是新的,但用于轻松部署应用程序的容器却是新的. 容器化越来 ...