App信息
包名:com.rytong.hnair

绕过强制更新
启动app,出现如下弹窗,强制更新

jadx反编译找到更新弹窗位置
搜索字符串立刻更新

双击跳转

这个字符串对应的资源名字是version_update__dialog_btn_confirm_text,搜索它,找到它被调用的位置

双击跳转
如下,在这里设置文本内容

通过查找用例跳转到上层方法


这里面的show()方法就是显示弹窗的,把它hook掉,弹窗就不会显示了
hook show()
1 2 3 4 5 6 7 8 9 10 11
| function hook_show() { Java.perform(function() { let k = Java.use("f6.k"); k["show"].implementation = function () { console.log(`k.show is called`); }; }); }
hook_show();
|
如下,弹窗就被hook掉了

抓包分析数据
点击登录,在通过了验证码校验之后会发送请求,及获取响应,抓取数据包

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| url=https://app.hnair.com/appum/common/auth/login?hnairSign=0564996701D210B22DBB6F7AAC619C260CA0A114
params={ "hnairSign": "0564996701D210B22DBB6F7AAC619C260CA0A114" } headers = { "appver": "9.0.0", "content-type": "application/json; charset=UTF-8", "content-length": "978", "accept-encoding": "gzip", "user-agent": "okhttp/4.9.1" }
json = { "common": { "akey": "184C5F04D8BE43DCBD2EE3ABC928F616", "aname": "com.rytong.hnair", "atarget": "standard", "aver": "9.0.0", "did": "e574bb78db98d8ea", "dname": "Google_Pixel 3", "gtcid": "514490d4a99745bba1ee3c67a21e5db6", "mchannel": "huawei", "schannel": "AD", "slang": "zh-CN", "sname": "google/blueline/blueline:10/QQ3A.200705.002/6506677:user/release-keys", "stime": "1740304439444", "sver": "10", "system": "AD", "szone": "+0800", "abuild": "64249", "riskToken": "67baf03fNy5MXBFAoCK6UHULA4nAOmGMshN11oP3", "captchaToken": "3037239175221CB99962A4E18B9A763B241E38AEC7657CDE570574B886AB788BAD219143A251B3B95BBEB9D693FDDAEED872D366E0D38095458726DDE75C845A49F1A6FEB95AE56461B44FC60507BA52:67baf0340PiDJ4ft549lxVciFEip4Qz9R8ox1Ra3", "hver": "9.0.0.35417.7ac793f2e.standard" }, "data": { "number": "18888888888", "pin": "dNKwvxEU5MhDIHvDxC9W3GkIe9Y9Qgn1GFIL2Rnl3lpIYOAUAHyAfcX7SuEvKD3fZUNb8oHkG2fh\njMktd9dIib489LGK65FO41So6mzRK+mn/5wqHzqSj0oFiBTJOkQ8aPpUNLoNKCLClYrS5q4aWhB6\n7ncdYn8dobgaz7TyjVk=\n", "toSave": true } }
|
要逆向分析的是hnairSign
参数分析
jadx反编译
搜索hnairSign

hnairSign
在如下位置出现

hnairSign它的值是从signRequest()方法返回的
signRequest()

这里面从参数aVar里面获取headersForSign、queryForSign、requestBodyForSign及生成参数str和a10,然后把这些参数传递个getHNASignature()方法,其返回值再传递给i.p()方法,i.p()的返回值应该是一个数组类型,然后获取第一个元素。
getHNASignature()

这是一个native方法,返回值是一个字符串
i.p()

这里面是根据字节数组strArr对charSequence返回一个List,最后通过get(0)获取第0个元素作为signRequest()方法的返回值。
hook getHNASignature()
1 2 3 4 5 6 7 8 9 10 11 12 13
| function getHNASignature() { Java.perform(function() { let HNASignature = Java.use("com.rytong.hnair.HNASignature"); HNASignature["getHNASignature"].implementation = function (str, str2, str3, str4, str5) { console.log(`HNASignature.getHNASignature is called: str=${str}, str2=${str2}, str3=${str3}, str4=${str4}, str5=${str5}`); let result = this["getHNASignature"](str, str2, str3, str4, str5); console.log(`HNASignature.getHNASignature result=${result}`); return result; }; }); }
getHNASignature();
|
hook结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| HNASignature.getHNASignature is called: str={}, str2={}, str3={"akey":"184C5F04D8BE43DCBD2EE3ABC928F616","aname":"com.rytong.hnair","atarget":"standard","aver":"9.0.0","did":"e574bb78db98d8ea","dname":"Google_Pixel 3","gtcid":"f442b091aa961a407165841e3a084147","mchannel":"huawei","schannel":"AD","slang":"zh-CN","sname":"google\/blueline\/blueline:10\/QQ3A.200705.002\/6506677:user\/release-keys","stime":"1740317961228","sver":"10","system":"AD","szone":"+0800","abuild":"64249","riskToken":"67bb2505kRG0Hwidai2tEm3hYFUX1xCXvH8fuOk3","hver":"9.0.0.35417.7ac793f2e.standard","number":"18888888888","pin":"awBta70HBNvOLA+L5Vlaas59trF+M0EI6lOgVDjQhG1QdoY\/6ck1GTaeZOeSXiwFpG3e8vgj6xuq\n1weM+DFKhl8aSi1Lhn7p1s51bdcPmvZ5DW3kYSV\/8DvpnYGjPKgQ79aKEBDo3AvuGZpZ+pg2rHBm\nWAgoyrVfSsBI6KLOsZg=\n","toSave":true}, str4=21047C596EAD45209346AE29F0350491, str5=F6B15ABD66F91951036C955CB25B069F HNASignature.getHNASignature
result=E184DAEE44DFA522CE974EAB75EBC60DAAEC321D>> 64249184C5F04D8BE43DCBD2EE3ABC928F616com.rytong.hnairstandard9.0.0e574bb78db98d8eaGoogle_Pixel 3f442b091aa961a407165841e3a0841479.0.0.35417.7ac793f2e.standardhuawei18888888888awBta70HBNvOLA+L5Vlaas59trF+M0EI6lOgVDjQhG1QdoY/6ck1GTaeZOeSXiwFpG3e8vgj6xuq 1weM+DFKhl8aSi1Lhn7p1s51bdcPmvZ5DW3kYSV/8DvpnYGjPKgQ79aKEBDo3AvuGZpZ+pg2rHBm WAgoyrVfSsBI6KLOsZg= 67bb2505kRG0Hwidai2tEm3hYFUX1xCXvH8fuOk3ADzh-CNgoogle/blueline/blueline:10/QQ3A.200705.002/6506677:user/release-keys174031796122810AD+0800true>>F6B15ABD66F91951036C955CB25B069F
result=515FCBCF21BD505882222C4898DCA5A13014C134>> 64249184C5F04D8BE43DCBD2EE3ABC928F616com.rytong.hnairstandard9.0.0e574bb78db98d8eaGoogle_Pixel 3f442b091aa961a407165841e3a0841479.0.0.35417.7ac793f2e.standardhuawei18888888888awBta70HBNvOLA+L5Vlaas59trF+M0EI6lOgVDjQhG1QdoY/6ck1GTaeZOeSXiwFpG3e8vgj6xuq 1weM+DFKhl8aSi1Lhn7p1s51bdcPmvZ5DW3kYSV/8DvpnYGjPKgQ79aKEBDo3AvuGZpZ+pg2rHBm WAgoyrVfSsBI6KLOsZg= 67bb2505kRG0Hwidai2tEm3hYFUX1xCXvH8fuOk3ADzh-CNgoogle/blueline/blueline:10/QQ3A.200705.002/6506677:user/release-keys174031796122810AD+0800true>>F6B15ABD66F91951036C955CB25B069F
|
hook signRequest()
两个方法一起hook
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| function getHNASignature() { Java.perform(function() { let HNASignature = Java.use("com.rytong.hnair.HNASignature"); HNASignature["getHNASignature"].implementation = function (str, str2, str3, str4, str5) { console.log(`HNASignature.getHNASignature is called: str=${str}, str2=${str2}, str3=${str3}, str4=${str4}, str5=${str5}`); let result = this["getHNASignature"](str, str2, str3, str4, str5); console.log(`HNASignature.getHNASignature result=${result}`); return result; }; }); }
getHNASignature();
function hook_signRequest() { Java.perform(function() { let ApiSignInterceptor = Java.use("com.hnair.airlines.repo.common.ApiSignInterceptor"); ApiSignInterceptor["signRequest"].implementation = function (aVar) { console.log(`ApiSignInterceptor.signRequest is called: aVar=${aVar}`); let result = this["signRequest"](aVar); console.log(`ApiSignInterceptor.signRequest result=${result}`); return result; }; }); }
hook_signRequest();
|
hook结果
1 2 3 4 5 6 7
| ApiSignInterceptor.signRequest is called: aVar=[object Object] HNASignature.getHNASignature is called: str={}, str2={}, str3={"akey":"184C5F04D8BE43DCBD2EE3ABC928F616","aname":"com.rytong.hnair","atarget":"standard","aver":"9.0.0","did":"e574bb78db98d8ea","dname":"Google_Pixel 3","gtcid":"f442b091aa961a407165841e3a084147","mchannel":"huawei","schannel":"AD","slang":"zh-CN","sname":"google\/blueline\/blueline:10\/QQ3A.200705.002\/6506677:user\/release-keys","stime":"1740318611305","sver":"10","system":"AD","szone":"+0800","abuild":"64249","riskToken":"67bb278f3kk3a3WeYbgRPyoBNPlIAdRaYordBAp3","hver":"9.0.0.35417.7ac793f2e.standard","number":"18888888888","pin":"YtirjBXqjfmcYkrHpTOw46uZtkKiQTt8RvSVGkZKby025\/m2Yrv1zMUHehUz+sEDkHENCIPyJGuR\nbqKOxirFsWuMr0W4vGizxLnHOOLh9BTxzMpjpPsihKYvEMS0DlRlxp86LsEXmjviAt55e4ByhkEu\nVq5ckk5NVufdx\/u7CFI=\n","toSave":true}, str4=21047C596EAD45209346AE29F0350491, str5=F6B15ABD66F91951036C955CB25B069F HNASignature.getHNASignature result=E2096151703457F87514E0067262519B8E6F6774>>64249184C5F04D8BE43DCBD2EE3ABC928F616com.rytong.hnairstandard9.0.0e574bb78db98d8eaGoogle_Pixel 3f442b091aa961a407165841e3a0841479.0.0.35417.7ac793f2e.standardhuawei18888888888YtirjBXqjfmcYkrHpTOw46uZtkKiQTt8RvSVGkZKby025/m2Yrv1zMUHehUz+sEDkHENCIPyJGuR bqKOxirFsWuMr0W4vGizxLnHOOLh9BTxzMpjpPsihKYvEMS0DlRlxp86LsEXmjviAt55e4ByhkEu Vq5ckk5NVufdx/u7CFI= 67bb278f3kk3a3WeYbgRPyoBNPlIAdRaYordBAp3ADzh-CNgoogle/blueline/blueline:10/QQ3A.200705.002/6506677:user/release-keys174031861130510AD+0800true>>F6B15ABD66F91951036C955CB25B069F ApiSignInterceptor.signRequest result=E2096151703457F87514E0067262519B8E6F6774
|
可以看到signRequest最终的返回结果就是>>符号分隔前的内容
so分析
在反编译代码里并没有显式的支出加载的so,需要自行定位
定位so
动态注册hook RegisterNatives()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| function hook_RegisterNatives() { var RegisterNatives_addr = null; var symbols = Process.findModuleByName("libart.so").enumerateSymbols(); for (var i = 0; i < symbols.length; i++) { var symbol = symbols[i].name; if ((symbol.indexOf("CheckJNI") == -1) && (symbol.indexOf("JNI") >= 0)) { if (symbol.indexOf("RegisterNatives") >= 0) { RegisterNatives_addr = symbols[i].address; console.log("RegisterNatives_addr: ", RegisterNatives_addr); } } } Interceptor.attach(RegisterNatives_addr, { onEnter: function (args) { var env = args[0]; var jclass = args[1]; var class_name = Java.vm.tryGetEnv().getClassName(jclass); var methods_ptr = ptr(args[2]); var method_count = args[3].toInt32(); console.log("RegisterNatives method counts: ", method_count); for (var i = 0; i < method_count; i++) { var name = methods_ptr.add(i * Process.pointerSize * 3).readPointer().readCString(); var sig = methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize).readPointer().readCString(); var fnPtr_ptr = methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2).readPointer(); var find_module = Process.findModuleByAddress(fnPtr_ptr); console.log("ClasssName: ", class_name, "MethodName: ", name, "Sig: ", sig, "Function_addr: ", fnPtr_ptr, "ModuleName: ", find_module.name, "Fun_Offset: ", ptr(fnPtr_ptr).sub(find_module.base)); } }, onLeave: function (retval) {} }); } hook_RegisterNatives()
|
在输出的结果中并没有找到,说明不是动态注册的
静态注册hook dlsym()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| function hook_dlsym(){ let dlsymAddr = Module.findExportByName("libdl.so","dlsym"); console.log(dlsymAddr); Interceptor.attach(dlsymAddr,{ onEnter:function(args){ this.args1 = args[1]; }, onLeave:function(retval){ let md= Process.findModuleByAddress(retval); if(md==null)return; console.log("function:"+this.args1.readCString(),"module:"+md.name,"address:"+retval,"offset:"+retval.sub(md.base)); } }) }
hook_dlsym()
|

找到so为libsignature.so
IDA反编译so
在静态函数中查找

双击跳转到函数位置,转换为伪代码

显示调用了HNASignature()然后调用了toString()
HNASignature()
查看其符号名,先对它进行hook

hook HNASignature()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function hook_HNASignature(){ let HNASignatureAddr = Module.findExportByName("libsignature.so", "_ZN12HNASignatureC2ERKSsS1_S1_S1_S1_"); Interceptor.attach(HNASignatureAddr,{ onEnter:function(args){ console.log("HNASignature is called"); console.log("HNASignature args[0]:"+args[0]); console.log("HNASignature args[1]:"+args[1].readPointer().readCString()); console.log("HNASignature args[2]:"+args[2].readPointer().readCString()); console.log("HNASignature args[3]:"+args[3].readPointer().readCString()); console.log("HNASignature args[4]:"+args[4].readPointer().readCString()); console.log("HNASignature args[5]:"+args[5].readPointer().readCString()); console.log("HNASignature args[6]:"+args[6]); this.args0 = args[0]; }, onLeave:function(){ console.log(`HNASignature ret this.args0:${this.args0.readPointer().readCString()}`); } }) }
|
hook 结果
1 2 3 4 5 6 7 8 9 10 11 12
| HNASignature is called HNASignature args[0]:0x75d9c78328 HNASignature args[1]:{} HNASignature args[2]:{} HNASignature args[3]:{"akey":"184C5F04D8BE43DCBD2EE3ABC928F616","aname":"com.rytong.hnair","atarget":"standard","aver":"9.0.0","did":"e574bb78db98d8ea","dname":"Google_Pixel 3","gtcid":"f442b091aa961a407165841e3a084147","mchannel":"huawei","schannel":"AD","slang":"zh-CN","sname":"google\/blueline\/blueline:10\/QQ3A.200705.002\/6506677:user\/release-keys","stime":"1740326030547","sver":"10","system":"AD","szone":"+0800","abuild":"64249","riskToken":"67bb4453hhA1OpIQxuFTcxvxY25l6alW4VgMhK73","hver":"9.0.0.35417.7ac793f2e.standard","number":"18888888888","pin":"qWIFqA0ywqaZqFsywFiTmniXYBKU8WpXlGexYUIhmKAXxOwf7\/z6NRN+sBj5d36igmPekmcESPWS\n4EbGmGLkCDM3al7NzoWqhucFcxl6n8gE6wfN83kqoS\/mJjQXis5WwixL\/wUpmYH8UzRaFunSsKsg\nW5WUx1CgTWdBpYUH3d0=\n","toSave":true} HNASignature args[4]:21047C596EAD45209346AE29F0350491 HNASignature args[5]:F6B15ABD66F91951036C955CB25B069F HNASignature args[6]:0xfefefefefefefeff HNASignature ret this.args0:2FD7C67C2ED04DE229D9D5C6B41534975DED3324>>64249184C5F04D8BE43DCBD2EE3ABC928F616com.rytong.hnairstandard9.0.0e574bb78db98d8eaGoogle_Pixel 3f442b091aa961a407165841e3a0841479.0.0.35417.7ac793f2e.standardhuawei18888888888qWIFqA0ywqaZqFsywFiTmniXYBKU8WpXlGexYUIhmKAXxOwf7/z6NRN+sBj5d36igmPekmcESPWS 4EbGmGLkCDM3al7NzoWqhucFcxl6n8gE6wfN83kqoS/mJjQXis5WwixL/wUpmYH8UzRaFunSsKsg W5WUx1CgTWdBpYUH3d0= 67bb4453hhA1OpIQxuFTcxvxY25l6alW4VgMhK73ADzh-CNgoogle/blueline/blueline:10/QQ3A.200705.002/6506677:user/release-keys174032603054710AD+0800true>>F6B15ABD66F91951036C955CB25B069F
|
在HNASignature()函数里出现了一堆函数

有尝试hook这些函数,信息量较大,后面有时间了分析,这里直接unidbg模拟执行了
unidbg模拟执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public class HNASignature extends AbstractJni { private final AndroidEmulator emulator; private final Memory memory; private final VM vm;
public HNASignature() { emulator = AndroidEmulatorBuilder .for64Bit() .build(); memory = emulator.getMemory(); memory.setLibraryResolver(new AndroidResolver(23)); vm = emulator.createDalvikVM(new File("unidbg-android/src/test/java/com/rytong/hnair/Hainan Airlines_9.0.0.apk")); vm.setJni(this); vm.setVerbose(true); vm.loadLibrary("signature",true); }
public String getHNASignature(){ DvmClass HNASignatureClass = vm.resolveClass("com.rytong.hnair.HNASignature"); DvmClass stringClass = vm.resolveClass("java.lang.String"); StringObject stringObject = HNASignatureClass.callStaticJniMethodObject(emulator, "getHNASignature(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", stringClass.newObject("{}").getValue(), stringClass.newObject("{}").getValue(), stringClass.newObject("{\"akey\":\"184C5F04D8BE43DCBD2EE3ABC928F616\",\"aname\":\"com.rytong.hnair\",\"atarget\":\"standard\",\"aver\":\"9.0.0\",\"did\":\"e574bb78db98d8ea\",\"dname\":\"Google_Pixel 3\",\"gtcid\":\"f442b091aa961a407165841e3a084147\",\"mchannel\":\"huawei\",\"schannel\":\"AD\",\"slang\":\"zh-CN\",\"sname\":\"google\\/blueline\\/blueline:10\\/QQ3A.200705.002\\/6506677:user\\/release-keys\",\"stime\":\"1740317961228\",\"sver\":\"10\",\"system\":\"AD\",\"szone\":\"+0800\",\"abuild\":\"64249\",\"riskToken\":\"67bb2505kRG0Hwidai2tEm3hYFUX1xCXvH8fuOk3\",\"hver\":\"9.0.0.35417.7ac793f2e.standard\",\"number\":\"18888888888\",\"pin\":\"awBta70HBNvOLA+L5Vlaas59trF+M0EI6lOgVDjQhG1QdoY\\/6ck1GTaeZOeSXiwFpG3e8vgj6xuq\\n1weM+DFKhl8aSi1Lhn7p1s51bdcPmvZ5DW3kYSV\\/8DvpnYGjPKgQ79aKEBDo3AvuGZpZ+pg2rHBm\\nWAgoyrVfSsBI6KLOsZg=\\n\",\"toSave\":true}").getValue(), stringClass.newObject("21047C596EAD45209346AE29F0350491").getValue(), stringClass.newObject("F6B15ABD66F91951036C955CB25B069F").getValue()); String ret = stringObject.getValue(); return ret; }
public static void main(String[] args) { HNASignature hnaSignature = new HNASignature(); ArrayList<String> list = new ArrayList<>(Arrays.asList(hnaSignature.getHNASignature().split(">>"))); System.out.println("getHNASignature(): "+hnaSignature.getHNASignature()); System.out.println("get(0): "+list.get(0)); } }
|
结果
1 2 3 4 5 6
| getHNASignature(): E184DAEE44DFA522CE974EAB75EBC60DAAEC321D>>64249184C5F04D8BE43DCBD2EE3ABC928F616com.rytong.hnairstandard9.0.0e574bb78db98d8eaGoogle_Pixel 3f442b091aa961a407165841e3a0841479.0.0.35417.7ac793f2e.standardhuawei18888888888awBta70HBNvOLA+L5Vlaas59trF+M0EI6lOgVDjQhG1QdoY/6ck1GTaeZOeSXiwFpG3e8vgj6xuq 1weM+DFKhl8aSi1Lhn7p1s51bdcPmvZ5DW3kYSV/8DvpnYGjPKgQ79aKEBDo3AvuGZpZ+pg2rHBm WAgoyrVfSsBI6KLOsZg= 67bb2505kRG0Hwidai2tEm3hYFUX1xCXvH8fuOk3ADzh-CNgoogle/blueline/blueline:10/QQ3A.200705.002/6506677:user/release-keys174031796122810AD+0800true>>F6B15ABD66F91951036C955CB25B069F
get(0): E184DAEE44DFA522CE974EAB75EBC60DAAEC321D
|