首页
社区
课程
招聘
[原创]一个简单的jeb字符串解密脚本
发表于: 2017-7-23 23:05 9633

[原创]一个简单的jeb字符串解密脚本

2017-7-23 23:05
9633

闲着没事学了一下2.*的jeb 脚本,大概1-2年前,大家都还是1.*的版本,但是现在2.*的api都变了好多,但是原理其实还是不变的(AST),所以就现学现卖,找了一个字符串加密的app做了实验,效果还是可以的。关于怎么学习这些api,其实跟着示例的几个script走一遍,稍微看一些文档,基本上就会用了。


这份代码主要针对的是解密函数唯一的加密方式,其中 methodname里可以自己定义解密的类的名字,decryptstring函数是对应的解密函数,这个脚本可能还不完善,但是我用着没问题了,大家可以多提提意见

from com.pnfsoftware.jeb.client.api import IScript, IconType, ButtonGroupType
from com.pnfsoftware.jeb.core import RuntimeProjectUtil
from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit
from com.pnfsoftware.jeb.core.units.code import ICodeUnit, ICodeItem
from com.pnfsoftware.jeb.core.output.text import ITextDocument
from com.pnfsoftware.jeb.core.units.code.java import IJavaSourceUnit, IJavaStaticField, IJavaNewArray, IJavaConstant, IJavaCall, IJavaField, IJavaMethod, IJavaClass
from com.pnfsoftware.jeb.core.events import JebEvent, J
from com.pnfsoftware.jeb.core.util import DecompilerHelper

import base64
import sys 
reload(sys)

sys.setdefaultencoding('utf-8') 

stringfilter=['aes error',]
methodname=['La/auu/a;','c']

class ReString(IScript):
    def run(self, ctx):
        print('start deal with strings')
        self.ctx = 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
        # means this is current project 
        prj=projects[0]   

        self.codeunits=RuntimeProjectUtil.findUnitsByType(prj , ICodeUnit,False)
        for codeUnit in self.codeunits:
            self.decompileForCodeUnit(codeUnit)

        units = RuntimeProjectUtil.findUnitsByType(prj, IJavaSourceUnit, False)
        for unit in units:
            javaClass = unit.getClassElement()
            print('[+] decrypt:'+javaClass.getName())
            self.cstbuilder = unit.getFactories().getConstantFactory()
            self.processClass(javaClass)
            unit.notifyListeners(JebEvent(J.UnitChange))
        print('Done.')
    
    def decompileForCodeUnit(self, codeUnit):
        decomp = DecompilerHelper.getDecompiler(codeUnit)
        allClasses = codeUnit.getClasses()
        if allClasses == None:
            return 
        for c in allClasses:
            # do not decompile inner classes
            if (c.getGenericFlags() & ICodeItem.FLAG_INNER) == 0:
                a = c.getAddress()
                srcUnit = decomp.decompile(a)

    def processClass(self ,javaClass):
        if javaClass.getName() == methodname[0]:
            print("find auu")
            return 
        for method in javaClass.getMethods():
            block=method.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):
            mmethod = e.getMethod()
            mname = mmethod.getName()
            msig = mmethod.getSignature()
            if mname == methodname[1] and methodname[0] in  msig :
                v=[]
                for arg in e.getArguments():
                    if isinstance(arg , IJavaConstant):
                        v.append(arg.getString())
                if len(v) == 1 :
                    decstr = self.decryptstring(v[0])
                    parent.replaceSubElement(e, self.cstbuilder.createString(decstr))

        for subelt in e.getSubElements():
            if isinstance(subelt, IJavaClass) or isinstance(subelt, IJavaField) or isinstance(subelt, IJavaMethod):
                continue
            self.checkElement(e,subelt)

    def decryptstring(self,string):
        src = []
        key = [69, 110, 99, 114, 121, 112, 116] 
        keylen = len(key)
        data = base64.decodestring(string)
        for index , char in enumerate(data):
            src.append( chr(ord(char) ^ key[index % keylen ]))

        return ''.join(src) 
        


###############################################
###
###  just for test 
###
################################################


                
    def processSourceTree(self, e):
        if e:
            self.analyzeNode(e)
            elts = e.getSubElements()
        for e in elts:
            self.processSourceTree(e)

    def getTextDocument(self, srcUnit):
        formatter = srcUnit.getFormatter()
        if formatter and formatter.getDocumentPresentations():
            doc = formatter.getDocumentPresentations()[0].getDocument()
        if isinstance(doc, ITextDocument):
            return doc
        return None

    def formatTextDocument(self, doc):
        javaCode, formattedMarks = '', ''
        # retrieve the entire document -it's a source file,
        # no need to buffer individual parts. 10 MLoC is enough 
        alldoc = doc.getDocumentPart(0, 10000000)
        for lineIndex, line in enumerate(alldoc.getLines()):
            javaCode += line.getText().toString() + '\n'
            for mark in line.getMarks():
                # 0-based line and column indexes
                formattedMarks += '%d:%d - %s (%s)\n' % (lineIndex, mark.getOffset(), mark.getName(), mark.getObject())
        return javaCode, formattedMarks

我这里找的app是*易的,大家可以自行下载他们家app, 他们的字符串方案很简单,就是采用了github上开源的stringforg ,然后自己改了一下密钥,实际就是一个base64 和抑或操作, 对于这些解密函数唯一的加密方式,其实很弱的,也可以用hook的方式改。但是比较蛋疼的是,我尝试用frida去hook好像失败了,可能是我姿势不大对。另外,有的加密可能会采用多种方式进行加密,这种其实也比较好破,基本上改一下我的代码,加入自定义的解密函数即可。

对于字符串这方面,个人还是倾向于dexguard那种,一个类一个解密函数,当然,那样其实也是可以通过jeb进行解密的。 github上有一个项目叫simplify,不知道并对没有,感觉这个挺厉害的,采用了虚拟执行的方式去解决字符串加密和一些混淆,但是目前应该还不算完善。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 0
支持
分享
最新回复 (7)
雪    币: 48
活跃值: (61)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
2
哦对,  关于字符串加解密这块,我个人觉得把,其实加密算法不用太强,抑或,取反其实都是可以的,像c层采用字节的形式也可以,我们要做的就是让逆向人员,第一眼看不错个所以然,一定要借助外力才能进行查看,另外,让对方找不到关键字也是一个措施。
2017-7-23 23:10
0
雪    币: 25
活跃值: (1111)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
3
针对网易的字符串混淆的话,操作smali要更加简单,而且是永久还原字符串
2017-7-24 17:02
0
雪    币: 48
活跃值: (61)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
4
繁华皆成空 针对网易的字符串混淆的话,操作smali要更加简单,而且是永久还原字符串
之前也想过改smali,不过之前加密字符串用过smali了,所以想换个玩法,正好学习一下的新的api
2017-7-24 17:50
0
雪    币: 43
活跃值: (85)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
smali  中还保留了.source  属性,用于还原的  api  变化较大
2017-7-25 09:47
0
雪    币: 210
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
问一下LZ 运行脚本提示这个错误是什么问题呢? 
Script error: Traceback (most recent call last):
  File "<string>", line 1, in <module>
2018-10-16 14:14
0
雪    币: 48
活跃值: (61)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
7
soonyou 问一下LZ 运行脚本提示这个错误是什么问题呢? Script error: Traceback (most recent call last): File "", lin ...
文件名要和类名一致,之前我也奇怪自己写的怎么导不进去,以为是有中文之类的,后来就发现这个坑了
2019-9-5 22:25
1
雪    币: 574
活跃值: (405)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
学习了
2019-9-6 11:12
0
游客
登录 | 注册 方可回帖
返回
//