(1) 如果混淆的类名中出现过于复杂的Aeabffdccdac
这种类型的类名,明显是经过手动更改的,所以有可能就是恶意的软件,因为大部分正规开发这只用商用的混淆器,混淆成 (a, b, c, etc.) 这种,不会过于复杂
eclipse配置jeb.jar包教程
import jeb.api.IScript;
import jeb.api.JebInstance;
public class jeb_javaScript implements IScript{
@Override
public void run(JebInstance instance) {
// TODO Auto-generated method stub
instance.print("sample java script of jeb");
}
}
导入Jar插件出错,manifest中没有JEB插件-类属性 产生错误,不能导入程序
JebPlugin-entryclass: jeb_javaScript
,不要使用Main-Class: jeb_javaScript
最后要保证清单文件中,至少包含这两个属性
ast
:抽象语法树,每一个节点代表源代码中的一种语法结构(while,if-else,return...)
Jeb_PythonScript.py
# coding: utf8
# 这个第三方库在jeb工具doc目录下的apidoczip包里,所以脚本需要存放在plugins目录里
from jeb.api import IScript
from jeb.api.dex import Dex
from jeb.api import EngineOption
from jeb.api.ui import View
from jeb.api.ast import Class, Field, Method, Call, Constant, StaticField, NewArray
# jeb根据文件名,实例化类,执行run函数来实现整个流程
class Jeb_PythonScript(IScript):
# jeb脚本的运行函数
def run(self, jeb):
# 获取当前运行的jeb对象
self.jeb = jeb
# 当前被jeb处理的dex文件对象
self.dex = jeb.getDex()
# 获取一个AST的实例对象(包含各种语法结构,if-else,return...)
self.constant = Constant.Builder(jeb)
# 指定需要扫描的类
self.scanClassname = 'Lfree//proxy/unblock/android/easy/app/c/c;'
# 可以使用dex.getClassSignatures获取所有被签名的类名,找到指定的类名
# 反编译指定类成java代码,来判断是否找到了该类
r = jeb.decompileClass(self.scanClassname)
# 解密方法的索引
self.decryptmethodindex = None
# 调用解密方法的方法列表
self.callDecryptmthodlist = None
# 根据加密函数中用到的字符列表的类型标识来填写
wanted_flags = Dex.ACC_STATIC|Dex.ACC_FINAL|Dex.ACC_PROTECTED
if not r:
print "could not find class %s" %self.scanClassname
# 获取这个类的抽象语法树对象
classASTobj = jeb.getDecompiledClassTree(self.scanClassname)
# 获取语法树对象的字段
for rootfield in classASTobj.getFields():
# 字段的签名(也就是声明的变量)
fieldsignlist = rootfield.getSignature().split('\n')
# 过滤出解密函数中用到的char类型列表
for siglefieldsign in fieldsignlist:
if siglefieldsign.endswith(':[C'):
fielddata = self.dex.getFieldData(siglefieldsign)
# 该字段的访问标识(i.e.protected static final char[] d;中的protected static final)
if fielddata.getAccessFlags() == wanted_flags:
print "find parameter character list : %s" %siglefieldsign
"""
根据解密需要的参数列表的引用情况,找到引用他的解密函数
遍历出所有调用这个解密方法的地方
然后执行解密函数,并用解密的结果替换调用地方的内容
"""
# 获取解密函数签名(完整路径),因为只取名字会有重复
listindex = fielddata.getFieldIndex()
# 根据提供的字段索引,检索出所有引用他的方法列表(列表中是方法的索引)
for siglemthodindex in self.dex.getFieldReferences(listindex):
# 获取这个索引所代表的原版方法
self.decryptmethodindex = siglemthodindex
methodname = self.dex.getMethod(siglemthodindex).getSignature(False)
if '' not in methodname and methodname != "":
self.decryptmethodname = methodname
print "*********************************************************************"
print "[+] found decrypt method: %s" %self.dex.getMethod(siglemthodindex).getSignature(False)
break
"""
获取所有函数对象,找到调用解密方法的地方
"""
# 根据解密方法的索引,获取调用这个解密方法的方法对象(int型的索引)列表
# callDecryptmthodlist:(DexMethod型)方法对象列表
referenceMethodList = self.dex.getMethodReferences(self.decryptmethodindex)
for sigleindex in referenceMethodList:
if self.callDecryptmthodlist == None:
self.callDecryptmthodlist = [self.dex.getMethod(sigleindex)]
else:
self.callDecryptmthodlist.append(self.dex.getMethod(sigleindex))
print "*********************************************************************"
for mobj in self.callDecryptmthodlist:
print "[+] find method which call decrypt method: %s" %mobj.getSignature(False)
print "*********************************************************************"
# 在这个调用解密方法的方法中,找到解密方法的具体位置
# 获取这个方法对象的抽象树上的所有元素节点
decryptElements = self.jeb.getDecompiledMethodTree(mobj.getSignature(True)).getSubElements()
#
# self.findPositionCallDecryptMthod(decryptElements)
self.findPositionCallDecryptMthod(decryptElements)
# 检查方法元素的各个节点,找到调用解密函数的具体位置
def findPositionCallDecryptMthod(self, dts):
# 解密方法的抽象语法树
call = None
# 遍历全部元素节点找到解密函数的调用地方
for i in dts:
# 如果当前元素节点不是一个方法调用对象,就遍历该元素节点内的所有节点
if not isinstance(i, Call):
subElements = i.getSubElements()
self.findPositionCallDecryptMthod(subElements)
continue
# 当前元素是函数调用对象的前提下,判断是否为解密函数
# 只能使用签名来判断,不能使用对象值来判断,因为对象字段如"jeb.api.dex.DexMethod@161b6ca"不一样,一个是调用函数对象,一个是声明函数对象)
if i.getMethod().getSignature() != self.decryptmethodname:
subElements = i.getSubElements()
self.findPositionCallDecryptMthod(subElements)
# print subElements
continue
call = i
# 获取其参数
if call != None:
for i in call.getArguments():
print i.getLeft().getLeft()
# 这里是解密方法,相当于将源码中的解密方法,赋值过来,和我最开始想的是,直接传入参数,调用反编译后的解密方法
def decrypt():
...
jeb1API文档 https://www.pnfsoftware.com/jeb1/apidoc/
https://rednaga.io/2017/10/28/hacking-with-dex-oracle-for-android-malware-deobfuscation/
# coding=utf-8
from com.pnfsoftware.jeb.client.api import IScript, IGraphicalClientContext
from com.pnfsoftware.jeb.core import RuntimeProjectUtil
from com.pnfsoftware.jeb.core.actions import Actions, ActionContext, ActionXrefsData
from com.pnfsoftware.jeb.core.events import JebEvent, J
from com.pnfsoftware.jeb.core.output import AbstractUnitRepresentation, UnitRepresentationAdapter
from com.pnfsoftware.jeb.core.units.code import ICodeUnit, ICodeItem
from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit, IJavaStaticField, IJavaNewArray, IJavaConstant, IJavaCall, IJavaField, IJavaMethod, IJavaClass
from urllib import unquote
from com.pnfsoftware.jebglobal import cm
import base64
"""解密指定类
1.遍历每个类的每个方法,提取里面包含解密函数的部分
2.实现解密函数
3.将第一步的解密部分替换成解密后的字符串
"""
sDecryptMethodName = u'nqjeQEdgDT'
class JEBSampleScript(IScript):
def run(self, ctx):
engctx = ctx.getEnginesContext()
if not engctx:
print('Back-end engines not initialized')
return
projects = engctx.getProjects()
if not projects:
print('There is no opened project')
return
prj = projects[0]
print('Decompiling code units of %s...' % prj)
self.codeUnit = RuntimeProjectUtil.findUnitsByType(prj, ICodeUnit, False)[0]
print(self.codeUnit)
# 1.遍历所有类和方法
units = RuntimeProjectUtil.findUnitsByType(prj, IJavaSourceUnit, False)
for unit in units:
javaClass = unit.getClassElement()
self.cstbuilder = unit.getFactories().getConstantFactory()
print("find class {} --> {}".format(javaClass.getName(), javaClass))
for oMethod in javaClass.getMethods():
self.replaceElement(oMethod)
print('finish!')
# 2.解密函数
def decrypt(self, sEnryptText):
# first decrypt
bUrldecodeText = bytearray(unquote(sEnryptText), encoding="utf-8")
# second decrypt
bKey = bytearray("OZLkiSmkmZ")
iKeyLen = len(bKey)
iUrldecodeTextLen = len(bUrldecodeText)
bDecryptText = bytearray(iUrldecodeTextLen)
v3 = 0
v4 = 0
while(v3 < iUrldecodeTextLen):
bDecryptText[v4] = bUrldecodeText[v3] ^ bKey[v4 % iKeyLen]
v3 += 1
v4 += 1
# third decrypt
if (len(bDecryptText) % 3) != 0:
bDecryptText.append("=")
return base64.b64decode(bDecryptText)
# 3.替换函数
def replaceElement(self, javaMethod):
block = javaMethod.getBody()
i = 0
while i < block.size():
stm = block.get(i)
self.checkElement(block, stm)
i += 1
def checkElement(self, parent, e):
if isinstance(e, IJavaCall):
mname = e.getMethod().getName()
if mname == sDecryptMethodName:
sArg = ""
if isinstance(e.getArguments()[0], cm):
print "sArg"
return
else:
sArg = e.getArguments()[0].getString()
decrypted_string = self.decrypt(sArg)
parent.replaceSubElement(e, self.cstbuilder.createString(decrypted_string))
print ' Decrypted string: %s' % repr(decrypted_string)
for subelt in e.getSubElements():
if isinstance(subelt, IJavaClass) or isinstance(subelt, IJavaField) or isinstance(subelt, IJavaMethod):
continue
self.checkElement(e, subelt)