如题本文主要讲某app登录算法还原并实现发包的全过程,此app非常适合小白入门时拿来练手, 一个无壳无混淆的app,软件链接我会放在文章最下面,建议先看一下文章后,再去下载上手。
首先将apk拖入jadx进行关键字LoginActivity搜索,然后进行分析得到下图代码, 是手机号加密码的发包位置,其中可见手机号和密码都被传入了login,跟踪进去后,可见的相关代码如下图。 这里login又调用的私有方法doLogin,将手机号和密码传给了UserService里面,我们进行追踪,得到如下图代码。 这里可以看到了密码登录参数,手机号和密码被传入了这里,密码被传进了getMD5后,加密后存入了params又传入了getRSAParams,然后传入request,先继续追踪getMD5, 是一个普通的MD5,用python进行一下复现,代码如下。
然后返回追进getRSAParams里面看到下图代码,一层base64加密,还有RSA加密。
先用frida来对这个对象动刀子,得结果如下
传入之前的密码,python复现的MD5结果相同,传入getRSAParams后成了后面的三项,data sign 和 timestamp,然后这些数据和charles抓包得到的login数据相同。
需要先解决data,进行追踪得到下图代码。Base64加密与解密。 对其进行python复现得到以下代码,运行结果与frida打印信息相同,
接着追踪sign的相关代码,得到下图代码
这里用frida进行hook,得到信息如下,可见这里是data与timestamp的拼接被传入了sign,被privateKey进行了加密,然后得到的sign。
然后sign的python还原,生成的结果与frida的hook结果相同,sign完成,然后就是将已经实现的python代码进行拼接,并完成发包。
先实现上图的login,实现手机号与密码的输入,传入parems,形成相同的login。 代码如下:
接着实现下图代码: 代码如下:
最后代码拼接一起,得到下面代码:
有部分简单的代码实现,以及开头通过objection的SSL屏蔽后charles进行抓包进行找的关键点,都没有在文章里面写,不过这些都是不必要的,所以文章是有一小部分省略。 整体对小白非常友好的软件,难度不算很高,只要花时间就可以掌握关键点,进行复现。 app放在有道云文章里面,想尝试一下的小白可以进去拿一下。 算法还原过程有道云文章链接:https://note.youdao.com/s/Yf9jGzqk
import
hashlib
def
get_md5(val):
m
=
hashlib.md5()
m.update(val.encode(
'utf-8'
))
result
=
m.hexdigest()
return
result
print
(get_md5(
"qwerty"
))
import
hashlib
def
get_md5(val):
m
=
hashlib.md5()
m.update(val.encode(
'utf-8'
))
result
=
m.hexdigest()
return
result
print
(get_md5(
"qwerty"
))
*
getRSAParams
is
called, params: {password
=
d8578edf8458ce06fbc5bb76a58c5ca4, os
=
android, mobile
=
15536263522
, version
=
2.2
.
3
}
getRSAParams ret value
is
{data
=
eyJwYXNzd29yZCI6ImQ4NTc4ZWRmODQ1OGNlMDZmYmM1YmI3NmE1OGM1Y2E0Iiwib3MiOiJhbmRyb2lkIiwibW9iaWxlIjoiMTU1MzYyNjM1MjIiLCJ2ZXJzaW9uIjoiMi4yLjMifQ
=
=
,
sign
=
DmxjCCvf8aJnZNve4BQkcy6turIGzkE13DkIu9JSnJF7yUDp3ZUxANRnSn6
+
BCN2nEogZsHFOm0fzzTU
/
NMnEqijA8lklHoxZspzVOe6Hkp8jYRrzvf0PQIh25lEL2GGWSslgzEK710opNDoQUVHA95ArOv9FQN95HxZuj7ywio
=
,
timestamp
=
1687264102
}
*
*
getRSAParams
is
called, params: {password
=
d8578edf8458ce06fbc5bb76a58c5ca4, os
=
android, mobile
=
15536263522
, version
=
2.2
.
3
}
getRSAParams ret value
is
{data
=
eyJwYXNzd29yZCI6ImQ4NTc4ZWRmODQ1OGNlMDZmYmM1YmI3NmE1OGM1Y2E0Iiwib3MiOiJhbmRyb2lkIiwibW9iaWxlIjoiMTU1MzYyNjM1MjIiLCJ2ZXJzaW9uIjoiMi4yLjMifQ
=
=
,
sign
=
DmxjCCvf8aJnZNve4BQkcy6turIGzkE13DkIu9JSnJF7yUDp3ZUxANRnSn6
+
BCN2nEogZsHFOm0fzzTU
/
NMnEqijA8lklHoxZspzVOe6Hkp8jYRrzvf0PQIh25lEL2GGWSslgzEK710opNDoQUVHA95ArOv9FQN95HxZuj7ywio
=
,
timestamp
=
1687264102
}
*
import
base64
import
json
def
encode(data, charset
=
'UTF-8'
):
datas
=
json.dumps(data,separators
=
(
','
,
':'
))
try
:
return
base64.b64encode(datas.encode(charset)).decode(charset)
except
Exception as e:
print
(
'Error'
, e)
return
None
data
=
{
"password"
:
"d8578edf8458ce06fbc5bb76a58c5ca4"
,
"os"
:
"android"
,
"mobile"
:
"15536263522"
,
"version"
:
"2.2.3"
}
result
=
encode(data)
print
(result)
import
base64
import
json
def
encode(data, charset
=
'UTF-8'
):
datas
=
json.dumps(data,separators
=
(
','
,
':'
))
try
:
return
base64.b64encode(datas.encode(charset)).decode(charset)
except
Exception as e:
print
(
'Error'
, e)
return
None
data
=
{
"password"
:
"d8578edf8458ce06fbc5bb76a58c5ca4"
,
"os"
:
"android"
,
"mobile"
:
"15536263522"
,
"version"
:
"2.2.3"
}
result
=
encode(data)
print
(result)
sign
is
called, content: data
=
eyJwYXNzd29yZCI6ImQ4NTc4ZWRmODQ1OGNlMDZmYmM1YmI3NmE1OGM1Y2E0Iiwib3MiOiJhbmRyb2lkIiwibW9iaWxlIjoiMTU1MzYyNjM1MjIiLCJ2ZXJzaW9uIjoiMi4yLjMifQ
=
=
×tamp
=
1687276955
,
privateKey: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMNGABIfN
+
iron2hbwB7mLK1Dm05V1qLZBILTDj7dypr
+
GJzQ9fk0V7gIIchpFG7pDQEXMbb2nj8VkNAIIDBaw7UY1h9n
+
sCBT
+
Xzz6BB2UxLBBMQVwOwv55tJkZ2YBcHFQDGz51HjxAonKJdHwGpjIp7bwdx375gybn2ic4qNuFAgMBAAECgYEAmcha7eqgASCKCx5DaMHtc2
+
bOPFblfcIjB1Rnd6L7mCxb
/
cOisutB2bCtykLW0LHAiAdYI5r87Ply3iJIF0yjU35I8aieDVmeaQXXQfpisimXLOmz6p4VlBzAkz493oXPEH81cHqbwnFkiFE3VVtHbCNoZqXlFWthIdae2kpjlECQQDyCMl09eyDBNGuzg1r4tAQ4CeZe7aCkEFwK2at76Raqz9NKrynBiZHsKLU3JedRm2eZ7JimUhsuKbbkS
/
mcxBrAkEAzop7
/
PyddSXGDFDECyuXtuEKyzzUvdGiyNmOexhSwTmTZ7QdQqe5p382yCQcY8RXxZ6W9CLjuukfa9I6Tcz
/
zwJAQbjpG318D8fLOHBzbIxWe36iwia51JJfcpoWc7zTIFvIAKhOOfyNgIISdULBWM
+
7DHyUD
/
oXlI4
/
oPe3zhgIqQJAQd3gFJnrDQTy19KZ8oYAaA30h0PrBG3qX
+
shiRgErCJUY
+
oIus0KY
+
Qp8EGz3A0tgJRGx6you17E6nmspksN
+
QJBAKhaBGeHqs0
+
Z5wtFcunuqc6hV7WlhBYCe5YSxBNSiaohXDr6nQwjiOY22Q3m8aInp9KS
+
lDwW0o4C58VARKyo8
=
sign ret value
is
Z5dDahgsBp06lh76v1fos8GSqX4HdcB
+
vJBJgw4qWN6wJ52T2LkX9e
/
WqtLrb
+
biSg10J23
/
f0KIQW57GFLIWEgLwQRWgKaacvJJVMtoeETAXhgMvYU9LWmjFzrtd1EuRLyHLVkWik7IbJM5mySllm
+
bG
/
nfcPvohXp6ATRqy7k
=
sign
is
called, content: data
=
eyJwYXNzd29yZCI6ImQ4NTc4ZWRmODQ1OGNlMDZmYmM1YmI3NmE1OGM1Y2E0Iiwib3MiOiJhbmRyb2lkIiwibW9iaWxlIjoiMTU1MzYyNjM1MjIiLCJ2ZXJzaW9uIjoiMi4yLjMifQ
=
=
×tamp
=
1687276955
,
privateKey: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMNGABIfN
+
iron2hbwB7mLK1Dm05V1qLZBILTDj7dypr
+
GJzQ9fk0V7gIIchpFG7pDQEXMbb2nj8VkNAIIDBaw7UY1h9n
+
sCBT
+
Xzz6BB2UxLBBMQVwOwv55tJkZ2YBcHFQDGz51HjxAonKJdHwGpjIp7bwdx375gybn2ic4qNuFAgMBAAECgYEAmcha7eqgASCKCx5DaMHtc2
+
bOPFblfcIjB1Rnd6L7mCxb
/
cOisutB2bCtykLW0LHAiAdYI5r87Ply3iJIF0yjU35I8aieDVmeaQXXQfpisimXLOmz6p4VlBzAkz493oXPEH81cHqbwnFkiFE3VVtHbCNoZqXlFWthIdae2kpjlECQQDyCMl09eyDBNGuzg1r4tAQ4CeZe7aCkEFwK2at76Raqz9NKrynBiZHsKLU3JedRm2eZ7JimUhsuKbbkS
/
mcxBrAkEAzop7
/
PyddSXGDFDECyuXtuEKyzzUvdGiyNmOexhSwTmTZ7QdQqe5p382yCQcY8RXxZ6W9CLjuukfa9I6Tcz
/
zwJAQbjpG318D8fLOHBzbIxWe36iwia51JJfcpoWc7zTIFvIAKhOOfyNgIISdULBWM
+
7DHyUD
/
oXlI4
/
oPe3zhgIqQJAQd3gFJnrDQTy19KZ8oYAaA30h0PrBG3qX
+
shiRgErCJUY
+
oIus0KY
+
Qp8EGz3A0tgJRGx6you17E6nmspksN
+
QJBAKhaBGeHqs0
+
Z5wtFcunuqc6hV7WlhBYCe5YSxBNSiaohXDr6nQwjiOY22Q3m8aInp9KS
+
lDwW0o4C58VARKyo8
=
sign ret value
is
Z5dDahgsBp06lh76v1fos8GSqX4HdcB
+
vJBJgw4qWN6wJ52T2LkX9e
/
WqtLrb
+
biSg10J23
/
f0KIQW57GFLIWEgLwQRWgKaacvJJVMtoeETAXhgMvYU9LWmjFzrtd1EuRLyHLVkWik7IbJM5mySllm
+
bG
/
nfcPvohXp6ATRqy7k
=
from
Crypto.
Hash
import
SHA
from
Crypto.Signature
import
pkcs1_15
from
Crypto.PublicKey
import
RSA
import
base64
def
sign(content, private_key):
private_key_value
=
base64.b64decode(private_key)
key
=
RSA.import_key(private_key_value)
hash_value
=
SHA.new(content.encode(
'utf-8'
))
k
=
1024
em_len
=
k
/
/
4
h_len
=
20
t_len
=
3
s_len
=
em_len
-
h_len
-
t_len
-
1
signature_value
=
pkcs1_15.new(key).sign(hash_value)[:s_len]
return
base64.b64encode(signature_value).decode()
content
=
"data=eyJwYXNzd29yZCI6ImQ4NTc4ZWRmODQ1OGNlMDZmYmM1YmI3NmE1OGM1Y2E0Iiwib3MiOiJhbmRyb2lkIiwibW9iaWxlIjoiMTU1MzYyNjM1MjIiLCJ2ZXJzaW9uIjoiMi4yLjMifQ==×tamp=1687276955"
private_key
=
'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMNGABIfN+iron2hbwB7mLK1Dm05V1qLZBILTDj7dypr+GJzQ9fk0V7gIIchpFG7pDQEXMbb2nj8VkNAIIDBaw7UY1h9n+sCBT+Xzz6BB2UxLBBMQVwOwv55tJkZ2YBcHFQDGz51HjxAonKJdHwGpjIp7bwdx375gybn2ic4qNuFAgMBAAECgYEAmcha7eqgASCKCx5DaMHtc2+bOPFblfcIjB1Rnd6L7mCxb/cOisutB2bCtykLW0LHAiAdYI5r87Ply3iJIF0yjU35I8aieDVmeaQXXQfpisimXLOmz6p4VlBzAkz493oXPEH81cHqbwnFkiFE3VVtHbCNoZqXlFWthIdae2kpjlECQQDyCMl09eyDBNGuzg1r4tAQ4CeZe7aCkEFwK2at76Raqz9NKrynBiZHsKLU3JedRm2eZ7JimUhsuKbbkS/mcxBrAkEAzop7/PyddSXGDFDECyuXtuEKyzzUvdGiyNmOexhSwTmTZ7QdQqe5p382yCQcY8RXxZ6W9CLjuukfa9I6Tcz/zwJAQbjpG318D8fLOHBzbIxWe36iwia51JJfcpoWc7zTIFvIAKhOOfyNgIISdULBWM+7DHyUD/oXlI4/oPe3zhgIqQJAQd3gFJnrDQTy19KZ8oYAaA30h0PrBG3qX+shiRgErCJUY+oIus0KY+Qp8EGz3A0tgJRGx6you17E6nmspksN+QJBAKhaBGeHqs0+Z5wtFcunuqc6hV7WlhBYCe5YSxBNSiaohXDr6nQwjiOY22Q3m8aInp9KS+lDwW0o4C58VARKyo8='
signature
=
sign(content, private_key)
print
(signature)
from
Crypto.
Hash
import
SHA
from
Crypto.Signature
import
pkcs1_15
from
Crypto.PublicKey
import
RSA
import
base64
def
sign(content, private_key):
private_key_value
=
base64.b64decode(private_key)
key
=
RSA.import_key(private_key_value)
hash_value
=
SHA.new(content.encode(
'utf-8'
))
k
=
1024
em_len
=
k
/
/
4
h_len
=
20
t_len
=
3
s_len
=
em_len
-
h_len
-
t_len
-
1
signature_value
=
pkcs1_15.new(key).sign(hash_value)[:s_len]
return
base64.b64encode(signature_value).decode()
content
=
"data=eyJwYXNzd29yZCI6ImQ4NTc4ZWRmODQ1OGNlMDZmYmM1YmI3NmE1OGM1Y2E0Iiwib3MiOiJhbmRyb2lkIiwibW9iaWxlIjoiMTU1MzYyNjM1MjIiLCJ2ZXJzaW9uIjoiMi4yLjMifQ==×tamp=1687276955"
private_key
=
'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMNGABIfN+iron2hbwB7mLK1Dm05V1qLZBILTDj7dypr+GJzQ9fk0V7gIIchpFG7pDQEXMbb2nj8VkNAIIDBaw7UY1h9n+sCBT+Xzz6BB2UxLBBMQVwOwv55tJkZ2YBcHFQDGz51HjxAonKJdHwGpjIp7bwdx375gybn2ic4qNuFAgMBAAECgYEAmcha7eqgASCKCx5DaMHtc2+bOPFblfcIjB1Rnd6L7mCxb/cOisutB2bCtykLW0LHAiAdYI5r87Ply3iJIF0yjU35I8aieDVmeaQXXQfpisimXLOmz6p4VlBzAkz493oXPEH81cHqbwnFkiFE3VVtHbCNoZqXlFWthIdae2kpjlECQQDyCMl09eyDBNGuzg1r4tAQ4CeZe7aCkEFwK2at76Raqz9NKrynBiZHsKLU3JedRm2eZ7JimUhsuKbbkS/mcxBrAkEAzop7/PyddSXGDFDECyuXtuEKyzzUvdGiyNmOexhSwTmTZ7QdQqe5p382yCQcY8RXxZ6W9CLjuukfa9I6Tcz/zwJAQbjpG318D8fLOHBzbIxWe36iwia51JJfcpoWc7zTIFvIAKhOOfyNgIISdULBWM+7DHyUD/oXlI4/oPe3zhgIqQJAQd3gFJnrDQTy19KZ8oYAaA30h0PrBG3qX+shiRgErCJUY+oIus0KY+Qp8EGz3A0tgJRGx6you17E6nmspksN+QJBAKhaBGeHqs0+Z5wtFcunuqc6hV7WlhBYCe5YSxBNSiaohXDr6nQwjiOY22Q3m8aInp9KS+lDwW0o4C58VARKyo8='
signature
=
sign(content, private_key)
print
(signature)
import
hashlib
def
login(mobile, word):
params
=
{
"password"
: get_md5(word),
"os"
:
"android"
,
"mobile"
: mobile,
"version"
:
"2.2.3"
,
}
return
params
def
get_md5(val):
m
=
hashlib.md5()
m.update(val.encode(
'utf-8'
))
result
=
m.hexdigest()
return
result
mobile
=
input
(
"请输入16手机号:"
)
parem
=
input
(
"请输入密码:"
)
params
=
login(mobile,parem)
print
(params)
import
hashlib
def
login(mobile, word):
params
=
{
"password"
: get_md5(word),
"os"
:
"android"
,
"mobile"
: mobile,
"version"
:
"2.2.3"
,
}
return
params
def
get_md5(val):
m
=
hashlib.md5()
m.update(val.encode(
'utf-8'
))
result
=
m.hexdigest()
return
result
mobile
=
input
(
"请输入16手机号:"
)
parem
=
input
(
"请输入密码:"
)
params
=
login(mobile,parem)
print
(params)
def
jiaparams(params):
params_json
=
json.dumps(params,separators
=
(
','
,
':'
))
print
(
"json转成功:"
,params_json)
data
=
base64.b64encode(params_json.encode(
'utf-8'
)).decode(
'utf-8'
)
print
(
"data成功:"
,data)
signstr
=
f
"data={data}×tamp={times()}"
print
(
"时间戳:"
,times())
print
(
"拼接成功"
,signstr)
signss
=
sign(signstr, pey)
print
(
"sign成功"
,signss)
result
=
{}
result[
'data'
]
=
data
result[
'sign'
]
=
signss
result[
'timestamp'
]
=
times()
return
result
def
jiaparams(params):
params_json
=
json.dumps(params,separators
=
(
','
,
':'
))
print
(
"json转成功:"
,params_json)
data
=
base64.b64encode(params_json.encode(
'utf-8'
)).decode(
'utf-8'
)
print
(
"data成功:"
,data)
signstr
=
f
"data={data}×tamp={times()}"
print
(
"时间戳:"
,times())
print
(
"拼接成功"
,signstr)
signss
=
sign(signstr, pey)
print
(
"sign成功"
,signss)
result
=
{}
result[
'data'
]
=
data
result[
'sign'
]
=
signss
result[
'timestamp'
]
=
times()
return
result
import
requests
import
json
import
time
import
hashlib
from
Crypto.
Hash
import
SHA
from
Crypto.Signature
import
pkcs1_15
from
Crypto.PublicKey
import
RSA
import
base64
pey
=
'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMNGABIfN+iron2hbwB7mLK1Dm05V1qLZBILTDj7dypr+GJzQ9fk0V7gIIchpFG7pDQEXMbb2nj8VkNAIIDBaw7UY1h9n+sCBT+Xzz6BB2UxLBBMQVwOwv55tJkZ2YBcHFQDGz51HjxAonKJdHwGpjIp7bwdx375gybn2ic4qNuFAgMBAAECgYEAmcha7eqgASCKCx5DaMHtc2+bOPFblfcIjB1Rnd6L7mCxb/cOisutB2bCtykLW0LHAiAdYI5r87Ply3iJIF0yjU35I8aieDVmeaQXXQfpisimXLOmz6p4VlBzAkz493oXPEH81cHqbwnFkiFE3VVtHbCNoZqXlFWthIdae2kpjlECQQDyCMl09eyDBNGuzg1r4tAQ4CeZe7aCkEFwK2at76Raqz9NKrynBiZHsKLU3JedRm2eZ7JimUhsuKbbkS/mcxBrAkEAzop7/PyddSXGDFDECyuXtuEKyzzUvdGiyNmOexhSwTmTZ7QdQqe5p382yCQcY8RXxZ6W9CLjuukfa9I6Tcz/zwJAQbjpG318D8fLOHBzbIxWe36iwia51JJfcpoWc7zTIFvIAKhOOfyNgIISdULBWM+7DHyUD/oXlI4/oPe3zhgIqQJAQd3gFJnrDQTy19KZ8oYAaA30h0PrBG3qX+shiRgErCJUY+oIus0KY+Qp8EGz3A0tgJRGx6you17E6nmspksN+QJBAKhaBGeHqs0+Z5wtFcunuqc6hV7WlhBYCe5YSxBNSiaohXDr6nQwjiOY22Q3m8aInp9KS+lDwW0o4C58VARKyo8='
url
=
'https://api.langshiyu.com/user/v2/account/login'
def
md5(pwd_str):
md5_obj
=
hashlib.md5()
md5_obj.update(pwd_str.encode(
'utf-8'
))
return
md5_obj.hexdigest()
def
times():
return
str
(
int
(time.time()))
def
sign(content, private_key):
private_key_value
=
base64.b64decode(private_key)
key
=
RSA.import_key(private_key_value)
hash_value
=
SHA.new(content.encode(
'utf-8'
))
k
=
1024
em_len
=
k
/
/
4
h_len
=
20
t_len
=
3
s_len
=
em_len
-
h_len
-
t_len
-
1
signature_value
=
pkcs1_15.new(key).sign(hash_value)[:s_len]
return
base64.b64encode(signature_value).decode()
def
login(mobile, param):
params
=
{
"password"
: md5(param),
"os"
:
"android"
,
"mobile"
: mobile,
"version"
:
"2.2.3"
,
}
return
params
def
jiaparams(params):
params_json
=
json.dumps(params,separators
=
(
','
,
':'
))
print
(
"json转成功:"
,params_json)
data
=
base64.b64encode(params_json.encode(
'utf-8'
)).decode(
'utf-8'
)
print
(
"data成功:"
,data)
signstr
=
f
"data={data}×tamp={times()}"
print
(
"时间戳:"
,times())
print
(
"拼接成功"
,signstr)
signss
=
sign(signstr, pey)
print
(
"sign成功"
,signss)
result
=
{}
result[
'data'
]
=
data
result[
'sign'
]
=
signss
result[
'timestamp'
]
=
times()
return
result
mobile
=
input
(
"请输入16位手机号:"
)
parem
=
input
(
"请输入密码:"
)
params
=
login(mobile,parem)
paramss
=
jiaparams(params)
print
(
"发包内容:"
,paramss)
fb
=
requests.post(url, paramss)
print
(
"结果:"
,fb.text)bjsdm
import
requests
import
json
import
time
import
hashlib
from
Crypto.
Hash
import
SHA
from
Crypto.Signature
import
pkcs1_15
from
Crypto.PublicKey
import
RSA
import
base64
pey
=
'MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMNGABIfN+iron2hbwB7mLK1Dm05V1qLZBILTDj7dypr+GJzQ9fk0V7gIIchpFG7pDQEXMbb2nj8VkNAIIDBaw7UY1h9n+sCBT+Xzz6BB2UxLBBMQVwOwv55tJkZ2YBcHFQDGz51HjxAonKJdHwGpjIp7bwdx375gybn2ic4qNuFAgMBAAECgYEAmcha7eqgASCKCx5DaMHtc2+bOPFblfcIjB1Rnd6L7mCxb/cOisutB2bCtykLW0LHAiAdYI5r87Ply3iJIF0yjU35I8aieDVmeaQXXQfpisimXLOmz6p4VlBzAkz493oXPEH81cHqbwnFkiFE3VVtHbCNoZqXlFWthIdae2kpjlECQQDyCMl09eyDBNGuzg1r4tAQ4CeZe7aCkEFwK2at76Raqz9NKrynBiZHsKLU3JedRm2eZ7JimUhsuKbbkS/mcxBrAkEAzop7/PyddSXGDFDECyuXtuEKyzzUvdGiyNmOexhSwTmTZ7QdQqe5p382yCQcY8RXxZ6W9CLjuukfa9I6Tcz/zwJAQbjpG318D8fLOHBzbIxWe36iwia51JJfcpoWc7zTIFvIAKhOOfyNgIISdULBWM+7DHyUD/oXlI4/oPe3zhgIqQJAQd3gFJnrDQTy19KZ8oYAaA30h0PrBG3qX+shiRgErCJUY+oIus0KY+Qp8EGz3A0tgJRGx6you17E6nmspksN+QJBAKhaBGeHqs0+Z5wtFcunuqc6hV7WlhBYCe5YSxBNSiaohXDr6nQwjiOY22Q3m8aInp9KS+lDwW0o4C58VARKyo8='
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)