ios逆向分析进阶之关键字加密还原

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.1
Host: api.gifshow.com
Content-Type: application/x-www-form-urlencoded
Connection: keep-alive
X-REQUESTID: 7603933
Accept: application/json
User-Agent: kwai-ios
Accept-Language: zh-Hans-CN;q=1
Content-Length: 580
Accept-Encoding: gzip, deflate

access_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=e162bc6fe6b588027938ab497fd33dd9


access_token    2.001azZhGohp7gC7c212d77790PBR_H
client_key  56c3713c
country_code    cn
language    zh-Hans-CN;q=1
open_id 6140757656
platform    sina2.0
raw 1511322475686
secret  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,而且直接找引用根本找不到。
    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++rXoU4dY
R0iPpYbXqMdU2kpRIgrPlCZHgC6I14UxaRbQ1JBJNqUqLGCzYDNWyBywurLFapIjfFy8857iYQ8WNIP9KmZX4W
ysTgfnmJBO2ltVkYZaUAP7ljdlritTSQ5R7qGAmwYlj1Vw1W6NWSlRTJAhIPaIRRw8jsBTdRELpEdwAoTX+EeW
jsEPTNbyaCOkNYcBsZcBiI4sFdVCvSRfigVxaZdYN+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:1511579735417
hkms getSignatureStr::arg2:kKSDefaultSecurityIdentifier
hkm::self-value:KSRSAUtil
hkm::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:1511579735417
hkm::self-value:UIDevice
hkm::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完全照着跟,很容掉坑里。分析要重点关注流程,不能一位分析汇编代码。
  • 以上总结纯属个人意见,如果异议,欢迎留言。

本次实验纯属研究为目的,如有不妥请联系本人。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值