前言
经常做逆向的同学应该不陌生这个软件,头几天想分析一下太极的实现原理,看了一下,发现他对常用对字符串进行加密操作。
预览
算法
经过研究发现是使用了一个叫:StringFog 的插件,并且算法使用的是xor也没有做对应的修改。
知道了算法,那么解码起来就比较简单了,先使用IDEA写个解密脚本。
public class gs {
public static byte[] decode(byte[] arg7, String arg8) {
int v3 = 0;
for(int i = 0; v3 < arg7.length; ++i) {
if(i >= arg8.length()) {
i = 0;
}
arg7[v3] = ((byte)(arg7[v3] ^ arg8.charAt(i)));
++v3;
}
return arg7;
}
}
我当时是自己撸的,后面发现StringFog才知道源码 😓
Github算法可能会随着时间进行更新 此解码非永久有效
文章编写时间:2020-06-02
脚本
如何编写一个JEB脚本,其实很简单,但是要阅读大量的英文文档,并且没有找到对应的中文文档,只能硬着头皮读,对于为这样英语基础为零的菜鸟,真的是痛苦无比。
好在网上有前人写的demo,这里稍做修改就可以正常解码了。
#coding=utf-8
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
# 密码,转换成char类型数组
password = [88, 105, 97, 111, 109, 97, 111]
# 解码的方法报名 以及方法名
methodName = ['Landroid/a/rc;','a']
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
units = RuntimeProjectUtil.findUnitsByType(projects[0], 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 processClass(self ,javaClass):
if javaClass.getName() == methodName[0]:
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):
try:
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)
except:
print ('error')
def decryptstring(self,string):
src = []
keylen = len(password)
data = base64.decodestring(string)
for index , char in enumerate(data):
src.append( chr(ord(char) ^ password[index % keylen ]))
return ''.join(src).decode('unicode_escape')
效果
建议
- 解码函数直接丢到native层,包括xor算法
- 使用美团的方案对jeb抵抗,仅jadx处理压力比较大
- 一些核心的方法调用尽量考虑用线程回调,如rxjava,eventbus等
- bean文件要混淆啊
备注
参考文章: