De-obfuscation反混淆_解密字符串_ jeb script

小技巧

(1) 如果混淆的类名中出现过于复杂的Aeabffdccdac这种类型的类名,明显是经过手动更改的,所以有可能就是恶意的软件,因为大部分正规开发这只用商用的混淆器,混淆成 (a, b, c, etc.) 这种,不会过于复杂

 
13671484-e877272d35f11903.png

 

导出Jar包流程,简单的jeb脚本

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包时,如果使用默认的elipse配置的MANIFEST.MF,会报错
    导入Jar插件出错,manifest中没有JEB插件-类属性 产生错误,不能导入程序
    解决:入口类设置成类似这样:JebPlugin-entryclass: jeb_javaScript,不要使用Main-Class: jeb_javaScript
     
    13671484-8b396c33159304f4.png
     
 
13671484-09849f3b0e809985.png
2018-09-27_185634.png

 

 
13671484-b5dc9e1899608744.png
2018-09-27_185716.png


最后要保证清单文件中,至少包含这两个属性

 
13671484-2724bfc4a0465047.png
2018-09-27_190338.png

 

DecryptStrings

  • java的解密字符串脚本 -> 传送门
    这里根据JEB官网脚本传送门,来学习和编写

ast:抽象语法树,每一个节点代表源代码中的一种语法结构(while,if-else,return...)

source code

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/vpn/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 '<clinit>' 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/

jeb2/jeb3 API 对应的脚本

# 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)

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值