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
|