一、前言

   前几篇文章链接:

    DEX文件解析---1、dex文件头解析

    DEX文件解析---2、Dex文件checksum(校验和)解析

    DEX文件解析--3、dex文件字符串解析

    DEX文件解析--4、dex类的类型解析


二、DEX文件中的方法原型

    1、关于dex文件中方法原型的解析,需要知道怎么解析出字符串和类的类型,不明白的可以看我前几篇的解析。DEX文件中的方法原型定义了一个方法的返回值类型和参数类型,例如一个方法返回值为void,参数类型为int,那么在dex文件中该方法原型表示为V(I)(smaliV表示voidI表示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方法原型解析的更多相关文章

  1. APK程序Dex文件无源码调试方法讨论

    那些不靠谱的工具 先来说说那些不靠谱的工具,就是今天吭了我小半天的各种工具,看官上坐,待我细细道来.IDA pro IDA pro6.6之后加入了dex动态调试功能,一时间普天同庆.喜大普奔.兴奋之后 ...

  2. 遍历文件 创建XML对象 方法 python解析XML文件 提取坐标计存入文件

    XML文件??? xml即可扩展标记语言,它可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言. 里面的标签都是可以随心所欲的按照他的命名规则来定义的,文件名为roi.xm ...

  3. DEX文件解析--6、dex文件字段和方法定义解析

    一.前言    前几篇文章链接:       DEX文件解析---1.dex文件头解析       DEX文件解析---2.Dex文件checksum(校验和)解析       DEX文件解析--3. ...

  4. DEX文件解析--7、类及其类数据解析(完结篇)

    一.前言    前置技能链接:       DEX文件解析---1.dex文件头解析       DEX文件解析---2.Dex文件checksum(校验和)解析       DEX文件解析--3.d ...

  5. 插件化框架解读之Class文件与Dex文件的结构(一)

    阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 Class文件 Class文件是Java虚拟机定义并被其所识别的 ...

  6. DEX文件类型和虚拟机(摘抄)

    DEX文件类型是Android平台上可执行文件的类型. Dalvik是Google公司自己设计用于Android平台的Java虚拟机.Dalvik虚拟机是Google等厂商合作开发的Android移动 ...

  7. TP框架ajax U方法不解析怎么办?

    TP框架中ajax U方法不解析 ajax U方法不解析 ajax url不解析 问题: 造成问题原因: Js 存在单独的 js文件中和html分离了.造成不解析! 解决方法: 方法一:将js放到ht ...

  8. Dex文件方法数超过65536怎么破?

    你的应用中的Dex 文件方法数超过了最大值65536的上限,会提示你: UNEXPECTED TOP-LEVEL EXCEPTION:java.lang.IllegalArgumentExceptio ...

  9. Android平台dalvik模式下java Hook框架ddi的分析(2)--dex文件的注入和调用

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/77942585 前面的博客<Android平台dalvik模式下java Ho ...

随机推荐

  1. 使用Applescript、Automator和AfredWorkflow实现流式工作

    重要:本文不会提供标题中三个工具的详细使用教程,只会对它们的进行简要的介绍.更高妙的使用技巧读者应自行钻研. 参考资料: 两个关于Applescript和Automator使用的PDF:https:/ ...

  2. python中的bytes和str类型

    经过一上午的查找资料.大概理清楚了bytes类型和str类型的区别. bytes类型和str类型在呈现形式有相同之处,如果你print一个bytes类型的变量,会打印一个用b开头,用单引号括起来的序列 ...

  3. 一篇看懂Docker

    松勤教育2020.4.20 我要分享     Docker 是什么? Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口.它是目前最流行的 Linux 容器解决方案. Dock ...

  4. 解决mysql插入数据l出现"the table is full"的问题

    需要修改Mysql的配置文件my.ini,在[mysqld]下添加/修改两行:tmp_table_size = 256Mmax_heap_table_size = 256M

  5. [经验栈]C#监测IPv4v6网速及流量

    1.前言   最近做项目需要用到监测网速及流量,我经过百度和墙内谷歌都没能快速发现监测IPV6流量和网速的用例:也经过自己的一番查询和调试,浪费了不少时间,现在作为经验分享出来希望大家指正. 2.C# ...

  6. Java中设置多个Access-Control-Allow-Origin跨域访问

    1.如果服务端是Java开发的,添加如下设置允许跨域即可,但是这样做是允许所有域名都可以访问,不够安全. response.setHeader("Access-Control-Allow-O ...

  7. Perl入门(三)Perl的数组

    Perl数组的声明方式 Perl使用"@"符号声明一个数组:@array: 使用"()"或"qw()"声明数组中元素: 一个完整的声明方式为 ...

  8. 使用json-server与Mockjs搭建模拟服务

    为什么使用 在项目开发中,常常需要边写前端页面边写后端接口,但是后端接口服务往往是滞后于前端开发的,或者是不能及时提供的.出于前端开发的迅速和便捷去考虑,我们可以根据后端接口数据结构去模拟(mock) ...

  9. CentOS 7 安装VNC

    VNC需要系统安装的有桌面,可以进行下面操作安装GNOME 桌面. #列出的组列表里有GNOME Desktopyum grouplist | grep GNOME 安装 yum groupinsta ...

  10. vueX基础知识点笔记

    vuex是专门用来管理vue.js应用程序中状态的一个插件.他的作用是将应用中的所有状态都放在一起, 集中式来管理.需要声明的是,这里所说的状态指的是vue组件中data里面的属性.简单的来说, 它就 ...