您的位置:首页 > 移动开发 > IOS开发

某FM密码加密分析IOS

2018-01-09 11:42 1051 查看

某FM密码加密分析

个人感觉这个分析用的手段比较典型,所以记录下。个人感觉ios有些封装特点在逆向过程中还是要有一定的认识的,不然就真是分析半天头疼的不行了。

抓包分析可疑数据

这一部分大致说一下,大致看了以了一下,没有看到跟登录的手机号和密码相关的关键字。应该是加密了,倒是path路径有个passport-sign-mobile/v2的网址路径,不过这是后话,开始的时候没看到这里。不过个人感觉从这里入手,应该也不会太容易,不过应该也可行。

界面分析

既然抓不出来啥,我就分析下登录界面

<XMRegisterAndLoginView: 0x1308a2410; frame = (0 0; 320 460); gestureRecognizers = <NSArray: 0x1307a3dc0>; layer = <CALayer: 0x13084e910>>
|    |    |    |    |    |    |    | <UITextField: 0x13087aa00; frame = (40 30; 240 44); text = '18104849732'; clipsToBounds = YES; opaque = NO; gestureRecognizers = <NSArray: 0x130873d00>; layer = <CALayer: 0x130894920>>
|    |    |    |    |    |    |    |    | <UIView: 0x13099c850; frame = (0 2; 105 40); layer = <CALayer: 0x1305373d0>>
|    |    |    |    |    |    |    |    |    | <UIButton: 0x130742b60; frame = (0 0; 80 40); opaque = NO; tag = 100; layer = <CALayer: 0x130585e80>>
|    |    |    |    |    |    |    |    |    |    | <UIImageView: 0x130868ce0; frame = (60 13; 14 14); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1308ae3a0>>
|    |    |    |    |    |    |    |    |    |    | <UIButtonLabel: 0x130797e60; frame = (17 10.5; 30 19.5); text = '+86'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x13058bc90>>
|    |    |    |    |    |    |    |    |    | <UIView: 0x13092f0e0; frame = (90 10; 1 20); layer = <CALayer: 0x130958750>>
|    |    |    |    |    |    |    |    | <UITextFieldLabel: 0x1306a4380; frame = (105 0; 135 42.5); text = '18104849732'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x130833700>>
|    |    |    |    |    |    |    | <UITextField: 0x1309865c0; frame = (40 89; 240 44); text = 'fyg'; clipsToBounds = YES; opaque = NO; gestureRecognizers = <NSArray: 0x13088b9f0>; layer = <CALayer: 0x130556600>>
|    |    |    |    |    |    |    |    | <UIImageView: 0x1302f5290; frame = (0 7; 30 30); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1306b43d0>>
|    |    |    |    |    |    |    |    | <UITextFieldLabel: 0x130936840; fram
13131
e = (30 0; 210 42.5); text = '●●●'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x13075aef0>>
|    |    |    |    |    |    |    |    |    | <_UILabelContentLayer: 0x13092a690> (layer)
|    |    |    |    |    |    |    | <UIButton: 0x130889bd0; frame = (40 148; 240 40); opaque = NO; layer = <CALayer: 0x13084ffb0>>
|    |    |    |    |    |    |    |    | <UIButtonLabel: 0x1302f7920; frame = (104 10.5; 32 19.5); text = '登录'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x13063f460>>
|    |    |    |    |    |    |    |    |    | <_UILabelContentLayer: 0x13058d3d0> (layer)
|    |    |    |    |    |    |    | <UIButton: 0x1307fb070; frame = (220 194; 60 27); opaque = NO; layer = <CALayer: 0x13095da50>>
|    |    |    |    |    |    |    |    | <UIButtonLabel: 0x1307dbbb0; frame = (0 6.5; 60 14.5); text = '忘记密码?'; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x13098ae30>>
|    |    |    |    |    |    |    |    |    | <_UILabelContentLayer: 0x13075bed0> (layer)
|    |    |    |    |    |    |    | <UIView: 0x1309ae010; frame = (30 261; 260 20); layer = <CALayer: 0x13075c690>>
|    |    |    |    |    |    |    |    | <UILabel: 0x1305a3600; frame = (88 0; 84 20); text = '其他方式登录'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x13091a880>>
|    |    |    |


我这里用的工具是Frida写的一个界面的工具,为什么?因为这个东西,支持中文格式,很好用。当然如果用不惯可以用 cycript 或reveal等。

至于frida工具,可以参看我的博客ios逆向神器frida。

这里我们找到“登录”关键字,看到它所属的类XMRegisterAndLoginView。可以看到0x1308a2410是他的地址。

验证下

#cycript -p 程序名称
#[#0x1302f7920 setHidden:YES]


登录标签消失了。说明我们分析正确。

ida静态分析和动态验证

这里重点分析XMRegisterAndLoginView

-[XMRegisterAndLoginView dealloc]   __text  000000010023E5B4    000000A4            R   .   .   .   B   T   .
-[XMRegisterAndLoginView initWithFrame:]    __text  000000010023E658    000000A8            R   .   .   .   B   T   .
-[XMRegisterAndLoginView layoutSubviews]    __text  000000010023E700    000008B4            R   .   .   .   B   T   .
-[XMRegisterAndLoginView customInit]    __text  000000010023EFB4    00001C5C            R   .   .   .   B   T   .
-[XMRegisterAndLoginView resignTextfieldAllResponder]   __text  0000000100240C10    0000007C            R   .   .   .   B   T   .
-[XMRegisterAndLoginView becomeSelected]    __text  0000000100240C8C    00000080            R   .   .   .   B   T   .
-[XMRegisterAndLoginView tapPressed]    __text  0000000100240D0C    0000000C            R   .   .   .   .   T   .
-[XMRegisterAndLoginView registerButtonPressed] __text  0000000100240D18    000000B8            R   .   .   .   B   T   .
-[XMRegisterAndLoginView loginButtonPressed]    __text  0000000100240DD0    000000B8            R   .   .   .   B   T   .
-[XMRegisterAndLoginView forgetPasswordButtonPressed]   __text  0000000100240E88    000000B8            R   .   .   .   B   T   .
-[XMRegisterAndLoginView thirdPartyLoginPressed:]   __text  0000000100240F40    00000124            R   .   .   .   B   T   .
-[XMRegisterAndLoginView showLastLoginTip:] __text  0000000100241064    000001E4            R   .   .   .   B   T   .
-[XMRegisterAndLoginView updateCountryCode:]    __text  0000000100241760    000000B8            R   .   .   .   B   T   .
-[XMRegisterAndLoginView countryCode:]  __text  0000000100241818    000000B0            R   .   .   .   B   T   .
-[XMRegisterAndLoginView usernameTextField] __text  00000001002418C8    00000010            R   .   .   .   .   T   .
-[XMRegisterAndLoginView setUsernameTextField:] __text  00000001002418D8    00000014            R   .   .   .   .   T   .
-[XMRegisterAndLoginView passwordTextField] __text  00000001002418EC    00000010            R   .   .   .   .   T   .
-[XMRegisterAndLoginView setPasswordTextField:] __text  00000001002418FC    00000014            R   .   .   .   .   T   .
-[XMRegisterAndLoginView loginButton]   __text  0000000100241910    00000010            R   .   .   .   .   T   .
-[XMRegisterAndLoginView setLoginButton:]   __text  0000000100241920    00000014            R   .   .   .   .   T   .
-[XMRegisterAndLoginView forgetPasswordButton]  __text  0000000100241934    00000010            R   .   .   .   .   T   .
-[XMRegisterAndLoginView setForgetPasswordButton:]  __text  0000000100241944    00000014            R   .   .   .   .   T   .
-[XMRegisterAndLoginView delegate]  __text  0000000100241958    00000020            R   .   .   .   B   T   .
-[XMRegisterAndLoginView setDelegate:]  __text  0000000100241978    00000014            R   .   .   .   .   T   .
-[XMRegisterAndLoginView countryCodeButton] __text  000000010024198C    00000010            R   .   .   .   .   T   .
-[XMRegisterAndLoginView setCountryCodeButton:] __text  000000010024199C    00000014            R   .   .   .   .   T   .
-[XMRegisterAndLoginView .cxx_destruct] __text  00000001002419B0    0000012C            R   .   .   .   B   T   .


通过cycript lldb等各种工具,验证以上可以函数的功能。显而易见,loginButtonPressed登录按钮激发函数,passwordTextField获取密码框字符串。其他其实大概也从名字也能开出来。当然这里其实我在这走了一点弯路,因为thoes挂钩不上,我还以为分析错误了。搞了半天,但用cycript和lldb又验证了下上面一些函数才发现是正确的,这里离应该有反挂钩。反反挂钩也懒得做了,不用挂钩了。

void __cdecl -[XMRegisterAndLoginView loginButtonPressed](#928 *self, SEL a2)
{
#928 *v2; // x19
#927 *v3; // x0
void *v4; // x22
int v5; // w23
#927 *v6; // x0
void *v7; // x19

v2 = self;
objc_msgSend((void *)self, "resignTextfieldAllResponder");
v3 = ((#927 *(__cdecl *)(#928 *, SEL))objc_msgSend)(v2, "delegate");
v4 = (void *)objc_retainAutoreleasedReturnValue(v3);
v5 = (unsigned __int64)objc_msgSend(v4, "respondsToSelector:", "registerAndLoginViewDidClickedLogin");
objc_release(v4);
if ( v5 )
{
v6 = ((#927 *(__cdecl *)(#928 *, SEL))objc_msgSend)(v2, "delegate");
v7 = (void *)objc_retainAutoreleasedReturnValue(v6);
objc_msgSend(v7, "registerAndLoginViewDidClickedLogin");
JUMPOUT(objc_release);
}
}


这里registerAndLoginViewDidClickedLogin属于

XMRegisterAndLoginViewController registerAndLoginViewDidClickedLogin

void __cdecl -[XMRegisterAndLoginViewController registerAndLoginViewDidClickedLogin](#4797 *self, SEL a2)
{
#4797 *v2; // x19
#2972 *v3; // x0
void *v4; // x21
void *v5; // x0
void *v6; // x0
void *v7; // x22
void *v8; // x0
__int64 v9; // x24
#2972 *v10; // x0
void *v11; // x20
void *v12; // x0
void *v13; // x0
void *v14; // x21
void *v15; // x0
__int64 v16; // x22

v2 = self;
if ( (unsigned int)objc_msgSend((void *)self, "baseSanityCheck") )
{
v3 = ((#2972 *(__cdecl *)(#4797 *, SEL))objc_msgSend)(v2, "registerAndLoginInfo");
v4 = (void *)objc_retainAutoreleasedReturnValue(v3);
v5 = objc_msgSend(*((void **)v2 + 24), "usernameTextField");
v6 = (void *)objc_retainAutoreleasedReturnValue(v5);
v7 = v6;
v8 = objc_msgSend(v6, "text");
v9 = objc_retainAutoreleasedReturnValue(v8);
objc_msgSend(v4, "setUsername:", v9);
objc_release(v9);
objc_release(v7);
objc_release(v4);
v10 = ((#2972 *(__cdecl *)(#4797 *, SEL))objc_msgSend)(v2, "registerAndLoginInfo");
v11 = (void *)objc_retainAutoreleasedReturnValue(v10);
v12 = objc_msgSend(*((void **)v2 + 24), "passwordTextField");
v13 = (void *)objc_retainAutoreleasedReturnValue(v12);
v14 = v13;
v15 = objc_msgSend(v13, "text");
v16 = objc_retainAutoreleasedReturnValue(v15);
objc_msgSend(v11, "setLoginPassword:", v16);
objc_release(v16);
objc_release(v14);
objc_release(v11);
JUMPOUT(objc_msgSend);
}
}


发现这里只是给一个类XMRegisterAndLoginItem赋值

根据XMRegisterAndLoginItem loginpassword调用函数找到了XMRegisterAndLoginViewController requestSecurityLogin

当然这里是通过动态lldb验证的,因为这里调用的函数并不多。

LABEL_8:
v33 = objc_msgSend(v19, "registerAndLoginInfo");
v34 = (void *)objc_retainAutoreleasedReturnValue(v33);
v35 = (__int64)v34;
v36 = objc_msgSend(v34, "username");
v37 = objc_retainAutoreleasedReturnValue(v36);
objc_msgSend(v26, "setObject:forKey:", v37, CFSTR("account"));
objc_release(v37);
v38 = v35;
}
else
{
v39 = objc_msgSend(v24, "substringFromIndex:", 1LL);
v40 = objc_retainAutoreleasedReturnValue(v39);
v41 = objc_msgSend(v19, "registerAndLoginInfo");
v42 = (void *)objc_retainAutoreleasedReturnValue(v41);
v43 = v42;
v44 = objc_msgSend(v42, "username");
v45 = objc_retainAutoreleasedReturnValue(v44);
v46 = v45;
v47 = objc_msgSend(&OBJC_CLASS___NSString, "stringWithFormat:", CFSTR("%@-%@"), v40, v45);
v48 = objc_retainAutoreleasedReturnValue(v47);
objc_msgSend(v26, "setObject:forKey:", v48, CFSTR("account"));
objc_release(v48);
objc_release(v46);
objc_release(v43);
v38 = v40;
}
objc_release(v38);
v49 = objc_msgSend(v19, "registerAndLoginInfo");
v50 = (void *)objc_retainAutoreleasedReturnValue(v49);
v51 = v50;
v52 = objc_msgSend(v50, "loginPassword");
v53 = (void *)objc_retainAutoreleasedReturnValue(v52);
v54 = v53;
v55 = objc_msgSend(v53, "md5String");
v56 = objc_retainAutoreleasedReturnValue(v55);
objc_msgSend(v26, "setObject:forKey:", v56, CFSTR("password"));
objc_release(v56);
objc_release(v54);
objc_release(v51);
v57 = objc_msgSend(v19, "loginToken");
v58 = objc_retainAutoreleasedReturnValue(v57);
objc_msgSend(v26, "setObject:forKey:", v58, CFSTR("nonce"));
objc_release(v58);
v59 = objc_msgSend(&OBJC_CLASS___NSString, "securetyStringFromDictionary:", v26);
v60 = (void *)objc_retainAutoreleasedReturnValue(v59);
v61 = v60;
v62 = objc_msgSend(v60, "lowercaseString");
v63 = (void *)objc_retainAutoreleasedReturnValue(v62);
v64 = v63;
v65 = objc_msgSend(v63, "md5String");
v66 = objc_retainAutoreleasedReturnValue(v65);
objc_msgSend(v26, "setObject:forKey:", v66, CFSTR("signature"));
objc_release(v66);
objc_release(v64);
v67 = objc_msgSend(&OBJC_CLASS___NSJSONSerialization, "dataWithJSONObject:options:error:", v26, 1LL, 0LL);
v68 = objc_retainAutoreleasedReturnValue(v67);
v69 = objc_msgSend(&OBJC_CLASS___NSString, "alloc");
v70 = objc_msgSend(v69, "initWithData:encoding:", v68, 4LL);
v71 = v70;
v72 = objc_msgSend(&OBJC_CLASS___NSString, "RSAStringFromString:", v70);
v73 = (void *)objc_retainAutoreleasedReturnValue(v72);
v74 = v73;
v75 = objc_msgSend(v73, "dataUsingEncoding:", 4LL);
v76 = objc_retainAutoreleasedReturnValue(v75);
objc_msgSend(v17, "setPostData:", v76);


动态 在v67 = objc_msgSend(&OBJC_CLASS___NSJSONSerialization, “dataWithJSONObject:options:error:”, v26, 1LL, 0LL);上下断点

对应的汇编

00000101042C2C                 MOV             X0, X19
__text:0000000101042C30                 BL              _objc_release
__text:0000000101042C34                 ADRP            X8, #classRef_NSJSONSerialization@PAGE
__text:0000000101042C38                 LDR             X0, [X8,#classRef_NSJSONSerialization@PAGEOFF] ; void *
__text:0000000101042C3C                 ADRP            X8, #selRef_dataWithJSONObject_options_error_@PAGE
__text:0000000101042C40                 LDR             X1, [X8,#selRef_dataWithJSONObject_options_error_@PAGEOFF] ; char *
__text:0000000101042C44                 MOV             W3, #1
__text:0000000101042C48                 MOV             X2, X24
__text:0000000101042C4C                 MOV             X4, #0
__text:0000000101042C50                 BL              _objc_msgSend
__text:0000000101042C54                 MOV             X29, X29


#subr 0x0000000101042C50


这里我用了个超级断点的工具,可以自动根据偏移计算真实地址。感兴趣的可以在我的博客里面找到。

(lldb) po $x24
{
account = 1810484xxxx;
nonce = "6907381121332755797@bjc|bgi|d|fj";
password = 1aabac6d068eef6a7bad3fdf50a05cc8;
signature = 117af45c60a1b178934d9a6631567468;
}


通过分析password是密码md5后的值,acccount是登录手机号。

到这里其实比较清晰了。



这里还有个RSAStringFromString:

跟以下这个类相关

-[XMRSAEncryptor dealloc]   __text  0000000101293154    0000007C            R   .   .   .   B   T   .
-[XMRSAEncryptor initWithCertificationName:OfType:] __text  00000001012931D0    000000AC            R   .   .   .   B   T   .
-[XMRSAEncryptor encryptWithRawString:] __text  000000010129327C    000000F0            R   .   .   .   B   T   .
-[XMRSAEncryptor getPublicKey]  __text  000000010129336C    000001CC            R   .   .   .   B   T   .
-[XMRSAEncryptor RSAEncrypotoTheData:]  __text  0000000101293538    000002D0            R   .   .   .   B   T   .
-[XMRSAEncryptor certificationName] __text  0000000101293808    00000010            R   .   .   .   .   T   .
-[XMRSAEncryptor setCertificationName:] __text  0000000101293818    00000014            R   .   .   .   .   T   .
-[XMRSAEncryptor certificationType] __text  000000010129382C    00000010            R   .   .   .   .   T   .
-[XMRSAEncryptor setCertificationType:] __text  000000010129383C    00000014            R   .   .   .   .   T   .
-[XMRSAEncryptor toBeEncryptString] __text  0000000101293850    00000010            R   .   .   .   .   T   .
-[XMRSAEncryptor setToBeEncryptString:] __text  0000000101293860    00000014            R   .   .   .   .   T   .
-[XMRSAEncryptor .cxx_destruct] __text  0000000101293874    00000054            R   .   .   .   B   T   .


这里很容易可以得到密钥等关键信息。

id __cdecl -[XMRSAEncryptor RSAEncrypotoTheData:](#5934 *self, SEL a2, id a3)
{
id v3; // x19
#5934 *v4; // x20
__int64 v5; // x22
void *v6; // x19
void *v7; // x19
void *v8; // x0
void *v9; // x25
signed int v10; // w22
unsigned int v11; // w20
void *v12; // x0
__int64 v13; // x23
__int64 v14; // x26
unsigned __int64 v15; // x24
__int64 v16; // x21
char *v17; // x0
char *v18; // x2
void *v19; // x0
void *v20; // x22
int v21; // w20
void *v22; // x0
__int64 v23; // x0
void *v24; // x22
void *v25; // x20
void *v26; // x0
id v27; // x0
__int64 v28; // x0
__int64 v29; // x21
void *v30; // x0
__int64 v31; // x20
struct objc_object *v33; // [xsp-90h] [xbp-90h]
void *v34; // [xsp-78h] [xbp-78h]
void *v35; // [xsp-70h] [xbp-70h]
size_t v36; // [xsp-68h] [xbp-68h]

v3 = a3;
v4 = self;
v5 = objc_retain(a3, a2);
v35 = objc_msgSend((void *)v4, "getPublicKey");
v36 = SecKeyGetBlockSize();
v34 = malloc(v36);
bzero(v34, v36);
v6 = objc_msgSend(v3, "dataUsingEncoding:", 4LL);
objc_release(v5);
v7 = (void *)objc_retainAutoreleasedReturnValue(v6);
v8 = objc_msgSend(&OBJC_CLASS___NSNumber, "numberWithLong:", v36 - 11);
v9 = (void *)objc_retainAutoreleasedReturnValue(v8);
v10 = (unsigned __int64)objc_msgSend(v9, "intValue");
objc_release(v9);
v11 = vcvtpd_s64_f64((double)(unsigned __int64)objc_msgSend(v7, "length") / (double)v10);
v12 = objc_msgSend(&OBJC_CLASS___NSMutableData, "alloc");
v33 = (struct objc_object *)objc_msgSend(v12, "init");
if ( (signed int)v11 >= 1 )
{
v13 = 0LL;
v14 = 0LL;
v15 = v10;
v16 = v11;
do
{
v17 = (char *)objc_msgSend(v7, "length");
if ( v15 >= (unsigned __int64)&v17[v13] )
v18 = &v17[v13];
else
v18 = (char *)v15;
v19 = objc_msgSend(&OBJC_CLASS___NSNumber, "numberWithLong:", v18);
v20 = (void *)objc_retainAutoreleasedReturnValue(v19);
v21 = (unsigned __int64)objc_msgSend(v20, "intValue");
objc_release(v20);
v22 = objc_msgSend(v7, "subdataWithRange:", v14, v21);
v23 = objc_retainAutoreleasedReturnValue(v22);
v24 = (void *)objc_retainAutorelease(v23);
v25 = objc_msgSend(v24, "bytes");
v26 = objc_msgSend(v24, "length");
if ( !(unsigned int)SecKeyEncrypt(v35, 1LL, v25, v26, v34, &v36) )
objc_msgSend(v33, "appendBytes:length:", v34, v36);
objc_release(v24);
v14 += v15;
v13 -= v15;
--v16;
}
while ( v16 );
}
if ( v34 )
free(v34);
if ( v35 )
CFRelease(v35);
v27 = ((id (__cdecl *)(#5929 *, SEL, id))objc_msgSend)((#5929 *)&OBJC_CLASS___GTMBase64, "stringByEncodingData:", v33);
v28 = objc_retainAutoreleasedReturnValue(v27);
v29 = v28;
v30 = objc_msgSend(&OBJC_CLASS___NSString, "stringWithFormat:", CFSTR("%@"), v28);
v31 = objc_retainAutoreleasedReturnValue(v30);
objc_release(v29);
objc_release(v33);
objc_release(v7);
return (id)objc_autoreleaseReturnValue(v31);
}


总结

工具太多,如果不能灵活应用,往往容易走到死路。我个人感觉,千万不能根据关键字大量的验证猜测。因为用很多相似的类和方法,但我们的目标却不在这些中。为了避免走弯路,我们的分析思路一定要清晰。发包封装的特点往往是,seturl setdata setpost requset等步骤,这些步骤可能不再同一个方法中。setpost是这些当中的关键,虽然不能直接找setpost的方法,但一定要在确定的request请求附近关注setpost.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: