文章转载于:https://blog.csdn.net/heier_blue/article/details/126394023?spm=1001.2014.3001.5502
本文只作学习研究,禁止用于非法用途,否则后果自负,如有侵权,请告知删除,谢谢!
前言
某团 android app mtgsig
参数分析,美食列表接口,版本 11.9.405
这是分析的案例是1.5的版本,最新的版本的2.4目前也研究出来了
文章转载自:android app so 加密算法分析破解|mtgsig unidbg
charles 抓包
就是它,本文主要分析 mtgsig
参数
java 层分析
反编译 apk 全局搜索 mtgsig
,有个赋值点过去,查找用例
这里有 hashMap.put
点过去
这里先是调用了 getBuilder
函数,猜测是获取 url 参数等,在调用 makeHeader
此函数又调用了 NBridge.main 函数
NBridge.main
是个 native 函数
libmtguard.so 文件查找
在上述的 NBridge.java
文件里,并没有看到有,so 文件的加载,那 native 函数是在哪个 so 呢
- 1、可以使用 frida 等工具来分析
- 2、可以参考别人文章的逻辑来分析
- 3、可以自己根据经验来分析
根据经验查找也有多种方式,这里就假设你已经阅读了龙哥 csdn 的文章,那就肯定知道 main
函数同时也是初始化函数,既然是初始化哪加载 so
的逻辑,估计也在一起,没错就直接查找 main
函数的交叉引用
有多个但 111 是初始化直接点过去,该逻辑是在 initNative
函数里,查看交叉引用,哪里调用的
在这里调用,如果细心点就会发现,上面有个 if,根据名称可以猜测出来跟 so 相关,查看交叉引用
在 loadSo 函数里,有个 System.loadLibrary 逻辑,加载成功就 isLoaded = true;
MTGConfigs.MTG
的值正是 mtguard
frida hook
function getProcessId() {var androidProcess = Java.use('android.os.Process');return 'processId: ' + androidProcess.myTid() + ' - ';
}function hook() {var javaString = Java.use('java.lang.String');var NBridge = Java.use('com.meituan.android.common.mtguard.NBridge');var WTSign = Java.use('com.meituan.android.common.mtguard.wtscore.plugin.sign.core.WTSign');WTSign.makeHeader.implementation = function (a, b) {console.log(getProcessId(), 'WTSign.makeHeader.a: ', a);console.log(getProcessId(), 'WTSign.makeHeader.b: ', javaString.$new(a));var res = this.makeHeader(a, b);console.log(getProcessId(), 'WTSign.makeHeader.res: ', res);return res;}NBridge.main.implementation = function (a, b) {console.log(getProcessId(), 'NBridge.main.a: ', a);console.log(getProcessId(), 'NBridge.main.b: ', b);if (b.length === 3) {console.log(getProcessId(), 'NBridge.main.b.0: ', b[0]);console.log(getProcessId(), 'NBridge.main.b.1: ', b[1]);console.log(getProcessId(), 'NBridge.main.b.2: ', b[2]);} else {for (var i = 0; i < b.length; i++) {console.log(getProcessId(), 'NBridge.main.b.i: ', i, ' data: ', b[i]);}}var res = this.main(a, b);console.log(getProcessId(), 'NBridge.main.res: ', res);for (var j = 0; j < res.length; j++) {console.log(getProcessId(), 'NBridge.main.res.j: ', j, ' data: ', res[j]);}return res;}
}function main() {Java.perform(function () {hook();})
}setImmediate(main);// frida -UF -l hook.js
// frida -UF -l hook.js | tee hook.log
使用 frida hook
一下,看看 main 函数的输入输出是啥
main
函数有两个参数
- 1、int 203
- 2、object array,1、固定的 key,2、url相关参数,3、int 数字
下面使用 unidbg 运行 main 函数
unidbg
package com.xiayu.meituan;import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.Module;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.memory.Memory;import java.io.File;
import java.io.IOException;public class MtGsigTest extends AbstractJni {private final AndroidEmulator emulator;private final Module module;private final VM vm;private final DvmClass NBridge;public String apkPath = "apkPath";public String soPath = "soPath";private static LibraryResolver createLibraryResolver() {return new AndroidResolver(23);}private static AndroidEmulator createARMEmulator() {return AndroidEmulatorBuilder.for32Bit().build();}MtGsigTest() {emulator = createARMEmulator();final Memory memory = emulator.getMemory();memory.setLibraryResolver(createLibraryResolver());vm = emulator.createDalvikVM(new File(apkPath));vm.setVerbose(true);DalvikModule dm = vm.loadLibrary(new File(soPath), true);vm.setJni(this);dm.callJNI_OnLoad(emulator);module = dm.getModule();NBridge = vm.resolveClass("com/meituan/android/common/mtguard/NBridge");}public static void main(String[] args) throws IOException {MtGsigTest mtGsig = new MtGsigTest();mtGsig.destroy();}private void destroy() throws IOException {emulator.close();}
}
先把架子搭好,跑起来,没啥问题
call main 111
public void callMain111() {DvmObject<?> strRc = NBridge.callStaticJniMethodObject(emulator, "main(I[Ljava/lang/Object;)[Ljava/lang/Object;",111,new ArrayObject(vm.resolveClass("java/lang/object").newObject(null)));System.out.println("callMain111: " + strRc.getValue());
}
有了前面的分析经验,得知,需要先调用 main
初始化加载函数,跑起来
这里报了个错误,正常补环境即可,具体的值,可以使用 frida call
或者 jnitrace
获取
写文章之前博主已经补过一遍了,所以这里就直接贴上 frida hook 的代码
function call() {var currentApplication = Java.use("android.app.ActivityThread").currentApplication();var context = currentApplication.getApplicationContext();var PackageManager = context.getPackageManager();var getPackageInfo = PackageManager.getPackageInfo('com.sankuai.meituan', 64);var NBridge = Java.use('com.meituan.android.common.mtguard.NBridge');console.log('NBridge.getDfpId : ', NBridge.getDfpId());console.log('NBridge.getPicName : ', NBridge.getPicName());console.log('NBridge.getSecName : ', NBridge.getSecName());console.log('NBridge.getMtgVN : ', NBridge.getMtgVN());console.log('PackageManager.GET_SIGNATURES: ', PackageManager.GET_SIGNATURES.value);console.log('PackageInfo.versionCode : ', getPackageInfo.versionCode.value);console.log('context.getPackageCodePath : ', context.getPackageCodePath());
}
补完再次跑起来
这里又报了个错误,前面 frida call
出来了,直接加上
再次运行,就没啥问题了,结果也正常出来了
代码测试
import requestsurl = "https://apimeishi.meituan.com/meishi/filter/v8/deal/select?isDefaultSelectedFilter=true&wifi-name=&mrnVersion=1.2.490&shoppingmallid=&cityId=1&type=&userid=-1&uuid=000000000000061F472CE89E948AB928A2F51BB092C0AA166069840990766831&poisBeforeInsert=&wifi-cur=&queryId=44285B77-73F5-44E0-98D7-DC5F634265A3&mypos=%2C&wifi-mac=&optimus_risk_level=71&hasGroup=true&locCityId=1&lat=&newStyle=e&lng=&offset=0&mallWeight=&mallIdType=&globalId=&jumpTab=&wifi-strength=&sort=defaults&beacons=%5B%5D&jingangId=&mallFloor=&cateId=1&tagContent=&mallName=&sessionClickedPois=&mallId=&sessionImpressedPois=&silentRefresh=false&newFastScreen=&tagType=&indoors=&optimus_code=10&selectedCityId=1&revisonStrategy=a&ci=1&isLocal=1&mallType=&optimus_uuid=000000000000061F472CE89E948AB928A2F51BB092C0AA166069840990766831&version_name=12.2.204&areaId=-1&globalIdForTag=&cn_pt=RN&utm_source=yijia5&utm_medium=android&utm_term=1200020204&utm_content=61f472ce89e948ab928a2f51bb092c0aa166069840990766831&utm_campaign=AgroupBgroupC0E0Ghomepage_category2_1__a1__c-1024&msid=61f472ce89e948ab928a2f51bb092c0aa1660698409907668311660799751709&p_appid=10&__reqTraceID=0f9cbb78-7e3b-469d-83a0-0406523252ee"payload = {}
mtgsig = get_mtgsig(url, body="")headers = {"mtgsig": mtgsig,'yodaReady': 'native','request-belong': 'com.meituan.android.mrn.container.MRNBaseActivity','pragma-os': 'MApi 1.1 com.sankuai.meituan 12.2.204 yijia5 ONEPLUS_A5010; Android 8.1.0','pragma-mtid': 'D479ED2812615CD','User-Agent': 'AiMeiTuan /OnePlus-8.1.0-ONEPLUS A5010-2034-1080-420-12.2.204-1200020204-D479ED2812615CD-yijia5','isPrefetch': 'true','M-SHARK-TRACEID': '101000000000000061F472CE89E948AB928A2F51BB092C0AA166069840990766831565c9e1660799844476859bd6','userid': '-1','yodaVersion': '1.18.0.150','Host': 'apimeishi.meituan.com'
}response = requests.request("GET", url, headers=headers, data=payload)
print(mtgsig)
print(response.text)
运行结果:
{"a0":"2.4","a1":"9b69f861-e054-4bc4-9daf-d36ae205ed3e","a3":12,"a4":1660800132,"a5":"uv+uksu/vPC9lMiXND1pXsU5Gm+tlzFe+d9sSXleegxRauyGDbj/yR1J7AyIGGQ7YAEaWm/0kR4oOXqfDshKCA4Xjd1HlVglqWnQ8XV7A1UuHvC8zfOz/tP3EHR4tx0IWmP96ucEugk8c7CodjMgxvQZahC0+SLbSMRPaNOVOVFIYGpq0f8s1jk73f9z3CtOvhvO3oPyPLRXoly9tZ4LzsIx+pOP113IL5Tdvo9blUhcUi3fboqeS3yOe2MS9FqD7mZqWNIcL5nQMqgvCfI=","a6":0,"a7":"hEG1VpFrhBvpntte3QGRr39Dkea+/Eyd+BwufDgp7UoGEGyR2pkjMzXkR9O6He82jYvt8WBv+iVYMP17HM+2PMyiyLkEulz/52KCWqdmr5A=","a8":"eb90079454bca9d7bc97d1946de3ae7f5996f4183e2188df76d4c735","a9":"e28e56adVcbfsKh67Kh6K9/F7V+Pl2XPH/kNwmKBuNORA2YYwbtKfDl5rS+83GkZG0fC7ZFN4i8HPjmLxZybdJdF08AYspkIiQ+5LDcAiNO2/5mDIHjAXtWXn/hONO7ZiybqzGBqdMnskHMf3IJHoRbJtk2Zkbyfx4ibkFr+SFRNhysT1kLsNo8soh6jCLqODXRAQaQfhNU1wIQOwi1RWWPSkgy3W4y3zUdBzSs6ku2MGX/vv51UDkdSWSsUmipuR/RpW07pLirzIRzByHAdTJ9uoqPv/1YItp/9h8XMtMNXdvgCqco2vsFwCw/p04Tt+aEmb289","a10":"2,130","x0":1,"a2":"197ebd952058dd780d9f8873ceae397a"}