ios逆向分析进阶之关键字加密还原
来源:互联网 发布:淘宝网李宁专卖店 编辑:程序博客网 时间:2024/06/10 17:05
ios逆向分析进阶之关键字加密还原
衔接上一篇博客,这一片自主逆向了一个较坑的算法,感觉基本入门了:
- 文中使用工具:
- IDA,Xcode(主要用来静态分析代码)
- theos lldb debugserver(动态跟踪函数参数返回值)
- mac自带的日志查看工具(这里找了很多日志工具,感觉还是mac自带的控制台比较好用)
- ssh连接手机
- frida分析应用结构
- charles(http截取)
回顾流程
- 本次逆向重在总结思路,所以就不给出app名称。静态分析花费时间较长,相信一般都是这样。当然如果经验多了,关键字猜的准一点,分析时间会大大缩短。本次分析从一个基本对app默认规则了解较少的视角来分析,确保逆向思路准确或接近准确。过程尽量还原分析过程和流程。
- 砸壳过程其实显示是没有加密,但dump头文件却很奇怪,一度以为dump不出头文件,也是后来发现,app目录下就有。不过个人觉得,只要app没加密,头文件其实不重要了。我们直接反编译搜索就行了,当然前提是思路要清晰。
charles抓包
POST /rest/user/thirdPlatformLogin?appver=5.4.4.297&did=BDF77B98-E3CD-4C99-BA77-EA75EE21FC77&c=PP&ver=5.4&sys=ios9.3.2&mod=iPhone6%2C1&net=%E4%B8%AD%E5%9B%BD%E8%81%94%E9%80%9A_5 HTTP/1.1Host: api.gifshow.comContent-Type: application/x-www-form-urlencodedConnection: keep-aliveX-REQUESTID: 7603933Accept: application/jsonUser-Agent: kwai-iosAccept-Language: zh-Hans-CN;q=1Content-Length: 580Accept-Encoding: gzip, deflateaccess_token=2.001azZhGohp7gC7c212d77790PBR_H&client_key=56c3713c&country_code=cn&language=zh-Hans-CN%3Bq%3D1&open_id=6140757656&platform=sina2.0&raw=1511322475686&secret=dyUsRMKNXHmsDwmC3cIq%2FdhlAlreWTMlgW9iGIt63lGd06FI5uJNP3Mt0N6X19n8I90zJIYC6MW54GRWq2qr7Zz6ztpybrQg8J05hNDWL2ADNGPTnTPP0Z%2FDdxJ2Yjlhmse4lFAHNj7mlsNY1J6m52tE9E9c%2BBkR1K6OaCr69iiBKPFjciq%2BWSOTU17SXnWl6pJR80FAJ%2BgnBXkCiIvAaEs5Y%2BNRgvAbxdxFd6LOnrfLguX6%2F75nMIdIIR5P%2BfjTqjM3Ux%2FAGlTxHG4OhKnTSNV%2F%2BRUwkMi0naooCdnZ6uMrSRA7Kw5EedS1z4n0efCQ6xtYSYHglxJOastX%2BmKevQ%3D%3D&sig=e162bc6fe6b588027938ab497fd33dd9access_token 2.001azZhGohp7gC7c212d77790PBR_Hclient_key 56c3713ccountry_code cnlanguage zh-Hans-CN;q=1open_id 6140757656platform sina2.0raw 1511322475686secret dyUsRMKNXHmsDwmC3cIq/dhlAlreWTMlgW9iGIt63lGd06FI5uJNP3Mt0N6X19n8I90zJIYC6MW54GRWq2qr7Zz6ztpybrQg8J05hNDWL2ADNGPTnTPP0Z/DdxJ2Yjlhmse4lFAHNj7mlsNY1J6m52tE9E9c+BkR1K6OaCr69iiBKPFjciq+WSOTU17SXnWl6pJR80FAJ+gnBXkCiIvAaEs5Y+NRgvAbxdxFd6LOnrfLguX6/75nMIdIIR5P+fjTqjM3Ux/AGlTxHG4OhKnTSNV/+RUwkMi0naooCdnZ6uMrSRA7Kw5EedS1z4n0efCQ6xtYSYHglxJOastX+mKevQ==sig e162bc6fe6b588027938ab497fd33dd9
- 我们这里同样分析secret关键字,这里分析过程其实不重要了,其实也不能说不重要。我们在程序中搜索secret,发现和secret相关的字段比较多,这里其实也用到了猜测的方法。我们根据直觉和认识寻找,但是都比较坑,就不说了。其实到后来才知道,我们应该搜索KS开头的类,这个主程序代码类库命名的主要方式。因为这两个字母是app中文拼音的两个开头字母,刚开始有点找不着北。总之,最后没有找到相关的。
这时候峰回路转,我们需要改变搜索规则。考虑是否可以搜索api.gifshow.com网址,但发现往这个地址发的数据很多,不现实。但发现这里这个路径/rest/user/thirdPlatformLogin?只有这个包里利用这条路径。经过搜索。我们发现apipath这个字符串里包含了/rest/user/thirdPlatformLogin?。搜索引用。其实在这里又花了点时间,发现IDA不是特别会用。因为它这个引用会跳到一个object的结构里,然后又包含了这个apipath,而且直接找引用根本找不到。
原因是object c调用规则,它采用了obj_msgsend()消息机制传输字符串来寻找对应的结构和方法,是所以我们直接找引用分本没有。好吧。
这里就掉坑里,我放弃了正确的方法,转到分析界面寻找按钮响应事件去了。
-><_UIWebViewScrollView: 0x12fbeaa00; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = H; gestureRecognizers = <NSArray: 0x130ac0820>; layer = <CALayer: 0x130a41b30>; contentOffset: {0, -64}; contentSize: {320, 504}>--><UIWebView: 0x130ebf310; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x130e2d8c0>>---><WBSDKWebView: 0x1312a9510; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; layer = <CALayer: 0x12f7fa190>>----><UIView: 0x12f5f4fb0; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x12f799f20>>-----><WBSDKAuthorizeWebViewController: 0x13114df20>------><UIViewControllerWrapperView: 0x131040c50; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x130d0cb30>>-------><UINavigationTransitionView: 0x130aade80; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x130ac5a70>>--------><UILayoutContainerView: 0x130a4cbd0; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x131039dd0>; layer = <CALayer: 0x1310c71b0>>---------><UINavigationController: 0x12fbd5000>----------><KSNavigationController: 0x12fbd8200>-----------><KSRevealSideViewController: 0x13085e630>------------><UITransitionView: 0x130a24210; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x130d550a0>>-------------><UIWindow: 0x12f5a1850; frame = (0 0; 320 568); autoresize = W+H; gestureRecognizers = <NSArray: 0x12f5e19b0>; layer = <UIWindowLayer: 0x12f5e0fe0>>--------------><UIApplication: 0x12f58cb30>---------------><AppDelegate: 0x12f599c60>
- 这里显示的微博登录的一个界面,坑的是,管理按钮的根本不是本地的界面,而是weibo的sdk接口。我找了半天没找到响应时间在那。理论上应该能找到,但我在congtroller里面找半天后来果断放弃,回到了原来的路上。
IDA静态分析和各种动态分析
- 其实这里静态分析,其实这里就走到正途上。但前面确实花了不少时间,很是纠结。IDA上有一个神奇的界面,叫鱼眼视图,开始不知道是用来干啥的,看起来很怪,后来发现很强大。
走到了正途我们就捡紧要的说了
sel_apipath sub_1001AB000 KSLoginService loginWithContext:(id)arg1 id __cdecl -[KSPhoneLoginService processLoginResponse:context:](KSPhoneLoginService *self, SEL a2, id a3, id a4) // sel_processLoginResponse sub_1001AB2B0 KSLoginService loginWithContext KSLoginManager login sub_1003596AC id __cdecl -[KSPhoneLoginService processLoginResponse:context:](KSPhoneLoginService *self, SEL a2, id a3, id a4)
- 经过跳转引用和鱼眼视图的不断切换,我们发现了程序的主要逻辑。apipath 通过sub_1001AB000通过KSLoginService loginWithContext引用。然后回溯到了[KSPhoneLoginService processLoginResponse:context:]。之后又回到了KSLoginService loginWithContex,只不过中间变成经过sub_1001AB2B0。
这个时候要动态分析了,
分别挂钩KSLoginService loginWithContext
KSPhoneLoginService processLoginResponse:context:
%hook KSLoginService- (void *)loginWithContext:(void *)arg1{ NSString *string=@"hkms loginWithContext::arg1:"; NSString *stringcombine=[[NSString alloc] initWithFormat:@"%@,%@",string,arg1]; %log(stringcombine); string=[[NSString alloc] initWithFormat:@"%@,%@",@"hkms ::self-value",self]; %log(string); void* result=%orig;//(arg1 ,arg2,arg3); string=[[NSString alloc] initWithFormat:@"%@,%@",@"hkms ::result-value",result]; %log(string); return result;}%end
- 只剩成功的这一段了,反正经过日志分析,我们发现 KSPhoneLoginService processLoginResponse:context:没有进来。我们loginWithContext似乎和这个关键字相关。
为了验证我们的猜想,我们lldb跟进。
image list -o -f
找到模块地址基地址
br s -a 基地址+IDA分析偏移
下断
我们发现sub_1001AB000函数dataTaskWithRequest:cancellationToken执行后,我们的关键请求立马会被发送。
id __fastcall sub_1001AB000(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6, __int64 a7, __int64 a8, struct objc_object *a9) v29 = +[KSUHTTPTaskManager defaultTaskManager](&OBJC_CLASS___KSUHTTPTaskManager, "defaultTaskManager"); v30 = (void *)objc_retainAutoreleasedReturnValue(v29); v31 = objc_msgSend(v28, "token"); v32 = objc_retainAutoreleasedReturnValue(v31); v33 = v32; v34 = objc_msgSend(v30, "dataTaskWithRequest:cancellationToken:", v22, v32); v15 = (KSApiDotGifShowHTTPClient *)objc_retainAutoreleasedReturnValue(v34);
到这里已经比较近了。但还需要很多分析。应为这里传经来的都是类.
_text:00000001001AB1E0 BL _objc_msgSend__text:00000001001AB1E4 MOV X29, X29__text:00000001001AB1E8 BL _objc_retainAutoreleasedReturnValue__text:00000001001AB1EC MOV X25, X0__text:00000001001AB1F0 ADRP X8, #selRef_dataTaskWithRequest_cancellationToken_@PAGE__text:00000001001AB1F4 LDR X1, [X8,#selRef_dataTaskWithRequest_cancellationToken_@PAGEOFF] ; char *__text:00000001001AB1F8 MOV X0, X24 ; void *__text:00000001001AB1FC MOV X2, X21__text:00000001001AB200 MOV X3, X25__text:00000001001AB204 BL _objc_msgSend__text:00000001001AB208 MOV X29, X29__text:00000001001AB20C BL _objc_retainAutoreleasedReturnValue
挂钩得到了传经来的类,细节不说了,跟上面一样
%hook KSUHTTPTaskManager//这个管理器参数一就是KSUPOSTHTTPRequest 参数二BFCancellationToken- (void*)dataTaskWithRequest:(void*)arg1 cancellationToken:(void*)arg2{
- 经过了一大段分析,我们跟进了一步。但这里我用lldb动态把这个函数给跟了一遍,最后自己都醉了。
应为这一段不和静态分析的代码的执行过程完全一样,虽然找到了地方,参数也相似,但有很多跳转就像山上的猴子,简直是乱跳,没有逻辑。
最后放弃了全盘动态跟踪的想法,这也就是arm汇编和x86汇编的区别吧。
- 其实这里有点思路不清晰了,KSUPOSTHTTPRequest 知识发送请求的操作,我们的数据很有可能在这之前就完成,最后回到了sub_1001AB000
id __fastcall sub_1001AB000(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6, __int64 a7, __int64 a8, struct objc_object *a9){ __int64 v9; // x22 void *v10; // x19 void *v11; // x0 struct objc_object *v12; // x0 struct objc_object *v13; // x21 id v14; // x0 KSApiDotGifShowHTTPClient *v15; // x22 __int64 v16; // x0 void *v17; // x0 __int64 v18; // x20 void *v19; // x0 __int64 v20; // x21 void *v21; // x0 void *v22; // x21 void *v23; // x0 __int64 v24; // x23 void *v25; // x0 __int64 v26; // x22 id v27; // x0 void *v28; // x23 id v29; // x0 void *v30; // x24 void *v31; // x0 __int64 v32; // x0 __int64 v33; // x25 void *v34; // x0 SEL v35; // x1 id v36; // x2 unsigned __int64 v37; // x3 id v38; // x4 id v39; // x5 id v40; // x6 id v41; // x7 v9 = a1; v10 = (void *)objc_retain(a2, a2); if ( (unsigned int)objc_msgSend(v10, "isFaulted") ) { v11 = objc_msgSend(v10, "error"); v12 = (struct objc_object *)objc_retainAutoreleasedReturnValue(v11); v13 = v12; v14 = ((id (__cdecl *)(BFTask_meta *, SEL, id))objc_msgSend)( (BFTask_meta *)&OBJC_CLASS___BFTask, "taskWithError:", v12); v15 = (KSApiDotGifShowHTTPClient *)objc_retainAutoreleasedReturnValue(v14); v16 = (__int64)v13; } else { v17 = objc_msgSend(*(void **)(v9 + 32), "paramsFromContext:", *(_QWORD *)(v9 + 40)); v18 = objc_retainAutoreleasedReturnValue(v17); if ( (unsigned int)objc_msgSend(*(void **)(v9 + 32), "needAppendTimestampSecret") ) { v19 = objc_msgSend(*(void **)(v9 + 32), "_paramsWithTimestampSecret:", v18); v20 = objc_retainAutoreleasedReturnValue(v19); objc_release(v18); v18 = v20; } v21 = objc_msgSend(*(void **)(v9 + 32), "request"); v22 = (void *)objc_retainAutoreleasedReturnValue(v21); v23 = objc_msgSend(*(void **)(v9 + 32), "apiPath"); v24 = objc_retainAutoreleasedReturnValue(v23); objc_msgSend(v22, "setPath:", v24); objc_release(v24); objc_msgSend(v22, "setBodyParameter:", v18); objc_msgSend(*(void **)(v9 + 32), "additionSetupRequest:context:", v22, *(_QWORD *)(v9 + 40)); v25 = objc_msgSend(*(void **)(v9 + 32), "_transformResponseObjectBlock"); v26 = objc_retainAutoreleasedReturnValue(v25); objc_msgSend(v22, "setTransformResponseObject:", v26); objc_release(v26); v27 = ((id (__cdecl *)(BFCancellationTokenSource_meta *, SEL))objc_msgSend)( (BFCancellationTokenSource_meta *)&OBJC_CLASS___BFCancellationTokenSource, "cancellationTokenSource"); v28 = (void *)objc_retainAutoreleasedReturnValue(v27); v29 = ((id (__cdecl *)(KSUHTTPTaskManager_meta *, SEL))objc_msgSend)( (KSUHTTPTaskManager_meta *)&OBJC_CLASS___KSUHTTPTaskManager, "defaultTaskManager"); v30 = (void *)objc_retainAutoreleasedReturnValue(v29); v31 = objc_msgSend(v28, "token"); v32 = objc_retainAutoreleasedReturnValue(v31); v33 = v32; v34 = objc_msgSend(v30, "dataTaskWithRequest:cancellationToken:", v22, v32); v15 = (KSApiDotGifShowHTTPClient *)objc_retainAutoreleasedReturnValue(v34); objc_release(v33); objc_release(v30); objc_release(v28); objc_release(v22); v16 = v18; } objc_release(v16); objc_release(v10); return objc_autoreleaseReturnValue(v15, v35, v36, v37, v38, v39, v40, v41, a9);}
这段代码比较长,但是也比较重要,就全贴吧。
明显这里是加密关键:KSLoginService _paramsWithTimestampSecret。进去
id __cdecl -[KSLoginService _paramsWithTimestampSecret:](KSLoginService *self, SEL selm, id instr){ void *v3; // x19 void *datastr; // x0 void *datastr0; // x21 double ident0; // d0 我猜测这里是采用datastr溢出的方式的到ident0 void *raw0; // x0 __int64 raw; // x20 void *secret0; // x0 __int64 secret; // x21 KSApiDotGifShowHTTPClient *instr_encode; // x22 SEL instr_encode0; // x1 id instr_encode1; // x2 unsigned __int64 diguisign; // x3 id diguisign0; // x4 id v16; // x5 id base64result; // x6 id base64result0; // x7 struct objc_object *v20; // [xsp+40h] [xbp+10h] v3 = objc_msgSend(instr, "mutableCopy"); //id __cdecl -[VKAccessToken mutableCopy](VKAccessToken *self, SEL selm) datastr = objc_msgSend(&OBJC_CLASS___NSDate, "date"); datastr0 = (void *)objc_retainAutoreleasedReturnValue(datastr); objc_msgSend(datastr0, "timeIntervalSince1970"); //ident0不知是什么,突然出现这么个值,raw还不定时的变化 raw0 = objc_msgSend(&OBJC_CLASS___NSString, "stringWithFormat:", CFSTR("%ld"), (signed __int64)(ident0 * 1000.0));//拼接字符串,这里就一个,就是个类型转换 raw = objc_retainAutoreleasedReturnValue(raw0); objc_release(datastr0); secret0 = objc_msgSend(&OBJC_CLASS___UIDevice, "getSignatureStr:", raw); //经过测试这里已经完成了secret字符串的加密}
secret0 = objc_msgSend(&OBJC_CLASS___UIDevice, “getSignatureStr:”, raw);
//经过测试这里已经完成了secret字符串的加密
id __cdecl +[UIDevice getSignatureStr:](UIDevice_meta *self, SEL selm, id instr){ UIDevice_meta *v3; // x20 struct objc_object *weiRSA; // x0 __int64 weiRSA0; // x19 __int64 ident0; // x1 __int64 num0; // x21 KSUTaskMetaData *ksutaskmetadata; // x0 KSUTaskMetaData *ksutaskmetadata0; // x22 signed __int64 ident1; // x2 const __CFString *weiRSA1; // x20 struct objc_object *weiRSA2; // x20 __int64 num; // [xsp+8h] [xbp-38h] v3 = self; num = 0LL; weiRSA = +[KSRSAUtil getSignatureStr:identifier:error:]( &OBJC_CLASS___KSRSAUtil, "getSignatureStr:identifier:error:", instr, CFSTR("kKSDefaultSecurityIdentifier"), &num); weiRSA0 = objc_retainAutoreleasedReturnValue(weiRSA); num0 = objc_retain(num, ident0); ksutaskmetadata = objc_msgSend(&OBJC_CLASS___KSUTaskMetaData, "alloc"); ksutaskmetadata0 = objc_msgSend(ksutaskmetadata, "init"); -[KSUTaskMetaData setAction:](ksutaskmetadata0, "setAction:", 41LL); -[KSUTaskMetaData setStatus:](ksutaskmetadata0, "setStatus:", 1LL); objc_msgSend((void *)v3, "taskMetaData:addErrorInfo:", ksutaskmetadata0, num0); if ( weiRSA0 ) ident1 = 7LL; else ident1 = 8LL; if ( weiRSA0 ) weiRSA1 = (const __CFString *)weiRSA0; else weiRSA1 = &stru_1024ident740; -[KSUTaskMetaData setStatus:](ksutaskmetadata0, "setStatus:", ident1); objc_release(num0); weiRSA2 = (struct objc_object *)objc_retainAutoreleaseReturnValue(weiRSA1); objc_release(ksutaskmetadata0); objc_release(weiRSA0); return weiRSA2;}
weiRSA = +[KSRSAUtil getSignatureStr:identifier:error:](
&OBJC_CLASS___KSRSAUtil,
“getSignatureStr:identifier:error:”,
instr,
CFSTR(“kKSDefaultSecurityIdentifier”),
&num);
这里的结果就是secret
我们把这几个函数可以都挂一下,发现,返回值都是secret.
但最核心的是这个。
id __cdecl +[KSRSAUtil getSignatureStr:identifier:error:](KSRSAUtil_meta *self, SEL selm, id instr, id ident, id *a5){ id *errostr; // x21 id ident0; // x20 KSRSAUtil_meta *selfobj; // x22 void *instr_selm; // x19 __int64 v9; // x1 void *ident1; // x20 void *instr_encode; // x0 __int64 instr_encode0; // x0 __int64 instr_encode1; // x23 void *diguisign; // x0 void *diguisign0; // x21 void *NSSv; // x22 void *base64result; // x0 __int64 base64result0; // x23 KSApiDotGifShowHTTPClient *base64result1; // x22 void *v20; // x0 __int64 v21; // x0 SEL v22; // x1 id v23; // x2 unsigned __int64 v24; // x3 id v25; // x4 id v26; // x5 id v27; // x6 id v28; // x7 struct objc_object *v30; // [xsp+40h] [xbp+10h] errostr = a5; ident0 = ident; //这是一个字符串"KKSDefaultSecurityIdentifier" selfobj = self; instr_selm = (void *)objc_retain(instr, selm);//这个选择子还是getSignatureStr,要么输入还是这么个类,要么其他的类也是这个方法,看了下其他类没有这个方法 //这个instr为raw,为一串变化的字符串,目测跟时间有关,产生于上一层 ident1 = (void *)objc_retain(ident0, v9); if ( objc_msgSend(ident1, "length") )//计算字节长度 { instr_encode = objc_msgSend(instr_selm, "dataUsingEncoding:", 4LL);//静态调用本方法 instr_encode0 = objc_retainAutoreleasedReturnValue(instr_encode); instr_encode1 = instr_encode0; diguisign = objc_msgSend(selfobj, "getSignature:identifier:error:", instr_encode0, ident1, errostr); diguisign0 = (void *)objc_retainAutoreleasedReturnValue(diguisign); objc_release(instr_encode1); if ( diguisign0 ) { //这几个函数都是NSString里的库函数,也就是说,本地函数到此调用结束 NSSv = objc_msgSend(&OBJC_CLASS___NSString, "alloc"); base64result = objc_msgSend(diguisign0, "base64EncodedDataWithOptions:", 0LL);//NSData base64result0 = objc_retainAutoreleasedReturnValue(base64result); base64result1 = (KSApiDotGifShowHTTPClient *)objc_msgSend(NSSv, "initWithData:encoding:", base64result0, 4LL);//NNString objc_release(base64result0); } else { base64result1 = 0LL; } objc_release(diguisign0); } else if ( errostr ) { v20 = objc_msgSend(selfobj, "errorWithErrorType:", 3001LL);//错误类型,不用管 v21 = objc_retainAutoreleasedReturnValue(v20); base64result1 = 0LL; *errostr = (id)objc_autorelease(v21); } else { base64result1 = 0LL; } objc_release(ident1); objc_release(instr_selm); return objc_autoreleaseReturnValue(base64result1, v22, v23, v24, v25, v26, v27, v28, v30);}
函数名中有RSA,我还以为跟RSA相关。但根本没啥关系。
(1)加密要用公钥 (n,e)
m必须是整数(字符串可以取ascii值或unicode值),且m必须小于n。
所谓”加密”,就是算出下式的c:
m的e次方 ≡ c (mod n)
例如:公钥是 (3233, 17),鲍勃的m假设是65,那么可以算出下面的等式:
6517 ≡ 2790 (mod 3233)
于是,c等于2790。
(2)解密要用私钥(n,d)
拿到2790以后,就用私钥(3233, 2753) 进行解密。
cd ≡ m (mod n)
也就是说,c的d次方除以n的余数为m。现在,c等于2790,私钥是(3233, 2753)
2790的2753次方 ≡ 65 (mod 3233)
因为里面就是base64加密,可见代码注释。
我们把这几个函数验证下。
%hook KSLoginService- (void*)_paramsWithTimestampSecret:(void*)arg1{ NSString *string=@"hkms _paramsWithTimestampSecret::arg1:"; NSString *stringcombine=[[NSString alloc] initWithFormat:@"%@,%@",string,arg1]; //NSString * match=@"^((?!rest/user).)*$" //[NSPredicate predcateWithFormate:arg1,match] //%log(stringcombine); string=[[NSString alloc] initWithFormat:@"%@,%@",@"hkm::self-value",self]; stringcombine=[[NSString alloc] initWithFormat:@"%@,%@",stringcombine,string]; //%log(stringcombine); void* result=%orig;//(arg1 ,arg2,arg3); string=[[NSString alloc] initWithFormat:@"%@,%@",@"hkm::result-value",result]; stringcombine=[[NSString alloc] initWithFormat:@"%@,%@",stringcombine,string]; %log(stringcombine); return result;}%end%hook UIDevice//这里的返回值已经是sercret关键字加密后的形式了/*dp7RIvaOm/20vyL0eYCUqZP5los9YTlAPT/a0Bv6jlQfq2m3KfX9KuI/nEu771FIRLaxCvkaGA7++rXoU4dYR0iPpYbXqMdU2kpRIgrPlCZHgC6I14UxaRbQ1JBJNqUqLGCzYDNWyBywurLFapIjfFy8857iYQ8WNIP9KmZX4WysTgfnmJBO2ltVkYZaUAP7ljdlritTSQ5R7qGAmwYlj1Vw1W6NWSlRTJAhIPaIRRw8jsBTdRELpEdwAoTX+EeWjsEPTNbyaCOkNYcBsZcBiI4sFdVCvSRfigVxaZdYN+1oJdiksp8OOxyyDe6VAir15wf+1gcpVIiP7/fUxk0r5Q==*/+ (void*)getSignatureStr:(void*)arg1{ NSString *string=@"hkms getSignatureStr::arg1:"; NSString *stringcombine=[[NSString alloc] initWithFormat:@"%@,%@",string,arg1]; string=[[NSString alloc] initWithFormat:@"%@,%@",@"hkm::self-value:",self]; stringcombine=[[NSString alloc] initWithFormat:@"%@,%@",stringcombine,string]; //%log(stringcombine); void* result=%orig;//(arg1 ,arg2,arg3); string=[[NSString alloc] initWithFormat:@"%@,%@",@"hkm::result-value:",result]; stringcombine=[[NSString alloc] initWithFormat:@"%@,%@",stringcombine,string]; %log(stringcombine); return result;}%end
日志跟踪结果
10:13:59.000000 +0800 com_kwai_gif [1;36m[kuaishouhook] [m[0;36mTweak.xm:169[m [0;30;46mDEBUG:[m +[<KSRSAUtil: 0x102a4c270> getSignatureStr:0x160722db0 identifier:0x10257dcc0 error:0x16fd4a618]: hkms KSRSAUtil getSignatureStr::arg1:,1511579639518,hkms getSignatureStr::arg2:,kKSDefaultSecurityIdentifier,hkm::self-value:,KSRSAUtil,hkm::result-value:,RXyOXL3s1QvkStBtDFO65BRIkuak5pz6t/EQMRhEmy/htpBnHNdCykZYmy7xWXecJ+znh8/4CEsc/48yJepfDMJyvfwsZLb/lXLZBdQmo/irCCrCbHfxsosnD7WUg7kapj1sRcUdx7R6SCi9pPgopebo21Ag2MtRDqnVjt3HzQvaKZIukGD5mb1DGi0ZpDFRbRX7pLKKZbihupvEYkxsTqL36pKWgs50b8y56zyQlNI43Ts3LD27RYTnJLGjTCRrSMX9kakVtAIeHI+EQoIPiajtJa+MA74MvynCMh1FMXkv0xhj0+rY1T5Iu4TZIFYSHLjwzjEC40TPDVP4vB3frA==10:13:59.000000 +0800 com_kwai_gif [1;36m[kuaishouhook] [m[0;36mTweak.xm:121[m [0;30;46mDEBUG:[m +[<UIDevice: 0x1a1e546a8> getSignatureStr:0x160722db0]: hkms getSignatureStr::arg1:,1511579639518,hkm::self-value:,UIDevice,hkm::result-value:,RXyOXL3s1QvkStBtDFO65BRIkuak5pz6t/EQMRhEmy/htpBnHNdCykZYmy7xWXecJ+znh8/4CEsc/48yJepfDMJyvfwsZLb/lXLZBdQmo/irCCrCbHfxsosnD7WUg7kapj1sRcUdx7R6SCi9pPgopebo21Ag2MtRDqnVjt3HzQvaKZIukGD5mb1DGi0ZpDFRbRX7pLKKZbihupvEYkxsTqL36pKWgs50b8y56zyQlNI43Ts3LD27RYTnJLGjTCRrSMX9kakVtAIeHI+EQoIPiajtJa+MA74MvynCMh1FMXkv0xhj0+rY1T5Iu4TZIFYSHLjwzjEC40TPDVP4vB3frA==10:15:35.000000 +0800 com_kwai_gif [1;36m[kuaishouhook] [m[0;36mTweak.xm:169[m [0;30;46mDEBUG:[m +[<KSRSAUtil: 0x102a4c270> getSignatureStr:0x1604bbc70 identifier:0x10257dcc0 error:0x16fd4a0f8]: hkms KSRSAUtil getSignatureStr::arg1:1511579735417hkms getSignatureStr::arg2:kKSDefaultSecurityIdentifierhkm::self-value:KSRSAUtilhkm::resultvalue:qCdZPHdPQx/KW/jsJv6QVJcR4blEMlKWlOAYFtharNFuWuKjlkbiGoaCKrKUsFrewK3K6CJA0wX0UVBb/61A9lqulSX5IpxoARUCGO4YoLksWVAX2Gv4cDguPlWHIBkbMLKQm21RKKCADXf8NOQRQuLITYsulnOozxQvhHdeI3jbt1LzdKz/GbG7os3jdN9kRCZtxXe3f6gE5ejNq5ILjQPubATLeOoTiVI60HBO6Iq+j7YNHVf80Brixme/Q/NgJWKIvziBOxQ89EPhUEnyMgPVkH/Vqd9bvDKnXT21NZwAvrQwGv8heVp5ttzrqrswx1cfU8O52Lu6BuFxj96N6w==10:15:35.000000 +0800 com_kwai_gif [1;36m[kuaishouhook] [m[0;36mTweak.xm:121[m [0;30;46mDEBUG:[m +[<UIDevice: 0x1a1e546a8> getSignatureStr:0x1604bbc70]: hkms getSignatureStr::arg1:1511579735417hkm::self-value:UIDevicehkm::result-value:qCdZPHdPQx/KW/jsJv6QVJcR4blEMlKWlOAYFtharNFuWuKjlkbiGoaCKrKUsFrewK3K6CJA0wX0UVBb/61A9lqulSX5IpxoARUCGO4YoLksWVAX2Gv4cDguPlWHIBkbMLKQm21RKKCADXf8NOQRQuLITYsulnOozxQvhHdeI3jbt1LzdKz/GbG7os3jdN9kRCZtxXe3f6gE5ejNq5ILjQPubATLeOoTiVI60HBO6Iq+j7YNHVf80Brixme/Q/NgJWKIvziBOxQ89EPhUEnyMgPVkH/Vqd9bvDKnXT21NZwAvrQwGv8heVp5ttzrqrswx1cfU8O52Lu6BuFxj96N6w==11:15:35.000000 +0800 com_kwai_gif [1;36m[kuaishouhook] [m[0;36mTweak.xm:97[m [0;30;46mDEBUG:[m -[<KSLoginService: 0x1607618c0> _paramsWithTimestampSecret:0x1606d1da0]: hkms _paramsWithTimestampSecret::arg1:,{ "access_token" = "2.001azZhGohp7gC7c212d77790PBR_H"; "open_id" = 6140757656; platform = "sina2.0"; },hkm::self-value,<KSThirdPartyLoginService: 0x1607618c0>,hkm::result-value,{ "access_token" = "2.001azZhGohp7gC7c212d77790PBR_H"; "open_id" = 6140757656; platform = "sina2.0"; raw = 1511579735417; secret = "qCdZPHdPQx/KW/jsJv6QVJcR4blEMlKWlOAYFtharNFuWuKjlkbiGoaCKrKUsFrewK3K6CJA0wX0UVBb/61A9lqulSX5IpxoARUCGO4YoLksWVAX2Gv4cDguPlWHIBkbMLKQm21RKKCADXf8NOQRQuLITYsulnOozxQvhHdeI3jbt1LzdKz/GbG7os3jdN9kRCZtxXe3f6gE5ejNq5ILjQPubATLeOoTiVI60HBO6Iq+j7YNHVf80Brixme/Q/NgJWKIvziBOxQ89EPhUEnyMgPVkH/Vqd9bvDKnXT21NZwAvrQwGv8heVp5ttzrqrswx1cfU8O52Lu6BuFxj96N6w=="; }
突然发现把关键信息泄露了,算了,给细心的同学点福利吧。
总结
- 日志这东西以前不用,想在用了发现。挂钩的结果一定要标准清楚,用来在日志中方便查找。否则一片混乱,就真找不到北了。
- 分析过程中关键字可能不只一个,一般类似secret、password、username.道理相同。实在找不到可以看下路径里有没有特异性的字符。总之,就是要能找到这个地方,其他人应用较少。
- 一般找到引用后有两个问题:
1.找到大致位置后不能定位。
2.引用位置太多,基本看不完。 - 这时候除了利用鱼眼视图要注意两点:
1.动态调试前一定要理清思路,把参数传递和数据发送的动作分开来思考。因为这符合模块设计的思路。
2.挂钩和动态调试结合,静态分析的结果很多有片面性,如果lldb完全照着跟,很容掉坑里。分析要重点关注流程,不能一位分析汇编代码。 - 以上总结纯属个人意见,如果异议,欢迎留言。
本次实验纯属研究为目的,如有不妥请联系本人。
- ios逆向分析进阶之关键字加密还原
- 关于某ios app登录关键字加密分析
- 逆向工程之还原源代码演示
- iOS逆向之分析微信导航栏实现
- IOS逆向之旅
- iOS逆向 查看ipa包是否加密
- ios逆向工程-静态分析
- iOS逆向工程-静态分析
- iOS逆向工程-动态分析
- ios逆向工程-静态分析
- ios逆向工程-静态分析
- ios逆向工程-静态分析
- Android逆向之旅---分析某直播App的协议加密原理以及调用加密方法进行协议参数构造
- Android逆向之旅---某直播APP的协议加密原理分析以及调用加密方法进行协议参数构造
- 穿透还原的工作原理分析(逆向工程)--机器狗
- 穿透还原的工作原理分析(逆向工程)
- Android逆向分析源码中资源代码还原小工具
- Android逆向分析源码中资源代码还原小工具
- JavaWeb-Maven Profile切换数据库连接配置
- Azkaban安装(一)
- MyEclipse:An internal error occurred during: "Build Project". GC overhead limit exceeded
- idea中如何给类中的属性生成set和get方法
- unity日志查看器
- ios逆向分析进阶之关键字加密还原
- 指针作为参数传递的相关问题
- 两种将十进制转换成二进制的算法
- codeforces893A chess for three题解
- 数据结构实验之图论四:迷宫探索
- 文章标题
- STM32 GPIO I/O Compensation Cell
- 多线程
- tomcat stratup可执行文件闪退的解决办法