版本是8.32.0,2024/04/19发布的,侵权系删!!!
抓包就不抓了,每个包headers里面都有一个shield,格式是XYAAAAAQAAAAEAAABTAAAAUzUWEe0xG1IbD9/c+qCLOlKGmTtFa+lG434NfuFQTKRBzI2yneNkH53+rOYKz8Mi1cx+2KY3QQwYRWWLN7/z1S011Oc8PZAcZStVDuw6DCul1soQ
这个参数这个版本搜不到,它是通过okhttp3的Interceptor添加上去的,添加的位置在so层.这个app有点特殊,不能说太多,关键位置都打码了.此篇是删减版
既然是加密就得确认入参,先打印看看有哪些Interceptor,需要以spawn的形式启动,新版有libmsaoaidsec.so的frida反调试,拆开来是msa open aid security 不是读msao,很多人读错了,网上自行寻找过frida检测的方法,我这里不介绍.
hook验证发现是在com.xxxxx.shield.http.xxxHttpInterceptor类的intercept方法把shield添加上去的,传入的时候头部没有shield,下一个拦截器y62.b里出现了,所以是这个位置
有敏感信息,不展示
后续的unidbg中的入参来自这组hook的结果,这组是get请求,post请求自己hook一个,没什么区别,只是多传了组参数.
com.xxxxx.shield.http.xxxHttpInterceptor类下的intercept方法,是一个native方法,用的jadx1.5.0,感觉更新后反编译速度快了,不那么占内存了,搜索也不卡,快去试试吧!
图片不展示,有敏感信息
上面还有3个native方法,看名字的意思就知道初始化,用unidbg跑的话必须要先初始化,否则会跑不出结果或者异常结果,这得益于这个app没有把名字去掉可以看出来,有的没有这种init字眼,或者只有一个native方法,根据不同的入参数值来进行初始化,初始化和入参共一个函数,比如mt的和阿里的.网上也有unidbg的代码,我这里直接放代码了,后续用unidbg来还原算法
先确认下是哪个so
结果
libxyass.so,这个版本只有64位的so,拉到ida64先看一下

都是seg段,加固了,用sodump dump下来再修复,之前星球发过这个工具
dump下来的是正常的,上面的"进度条"变蓝了

同时可以看到这个so真正的名字是libshield.so
上面hook的结果中headers有很多参数,我测试过只有url,xy-common-params,xy-direction会影响最终结果,除了这些参数外,unidbg中补的环境也有影响结果的参数,deviceId和main_hmac.除此以外还有些小参数在xy-common-params会有体现,后面我们遇到的时候再说.
先trace一份结果,后面遇到需要trace的地方看这份结果就行了,时机的话选择so刚加载进来的位置

trace的结果10多万行,先放一边,这种入参那么多的肯定是从后往前推效果更好.
先从jni的日志中开始定位,0xbcf2c


这里newstringutf是将cstring转jstring,所以要追踪v89的来源,600多行直接找太麻烦,直接监控v89这块内存的写入
看下这处的汇编
BCF2C执行完后跳到13a18执行,13a18应该是newstringutf,这样的话x1就是第一个参数,下断看下

地址是0x40461018,监控这块内存的写入,最终结果是134字节

前两个字节是5859是XY拼接的,看后132字节就行了

[libc.so]0x1c1f8 pc指向libc的话一般用的是memcpy函数,直接看lr寄存器的位置就可以了,0x9f0f0

0x9f0f0的上一行memcpy,9F0EC下断看下内存地址,memcpy的第一个参数buffer,第二个源数据,第三个源数据长度,看第二个参数地址

继续监控0x4059a018

0x4bfac跳过去看一下

有base64 table,跳过去看了下是标准的,同时看到了v3 += 3LL;和v4 += 4;确实符合base64的是3字节转4字节数据,数据来源是a2,hook验证下是不是标准的,4BF44的第二个参数


验证了,是标准base64
第3个参数0x63是参数2的长度所以目标变成了追踪这0x63个字节,地址是0x40456098

还是之前的trace追踪方法

0x40593000,接着跟

发现前16字节和后面字节的赋值位置不一样,先看前面的,0x497b4

来自v4,v4来自a1,函数是sub_49650,在49650下断


是个指针,小端序

跟踪0x40453196偏移16字节的位置

0x4930c

上面的两个01是固定在so里面的,看后面的两个0x53,都来自于v7,v7和a1有关,看下a1是什么
sub_4926C

一个指针,指向0x4058e010

(*(*a1 + 20LL) + *(*a1 + 24LL) + *(*a1 + 28LL) + 24);这行代码的结果是0x53怎么来的?
0x07+0x24+0x10+0x18=0x53,前3个数字就是上图中的20,24,28位置的值,还要继续追吗?其实改改入参的话会发现这个结果始终是0x53,为了严谨点还是跟过去看看吧.
只需要3个字节就可了

0x49138

这个函数是sub_4908C,来自a2,a5,a7
a2和a5都是指针

长度是07,是build,在xy-common-params里面有

长度0x24,是deviceid

长度0x10,这个很重要,是后续魔改md5的最终结果,这个非常重要
除了这几个还有app_id,后续我不再这样跟了,出现的时候我说一声

0x497dc,都是赋值的位置,我们要找最初生成的位置,和上面一样的跟踪,这里不重复上面的内容了,只需定位一次就可定位到,在0x5126c


一轮8个字节,一共10轮,再加后序添加的3个字节,入参是a3,先看一眼入参

也是0x53个字节,后16字节是前面说到的md5的结果,ECFAAF01是app_id,在xy-common-params中有,
和上面跟踪0x53一样的思路,01,02是固定在so里的,07,24,10就是我们上面跟踪的,中间的结果由build+deviceid拼接成.所以最终的目标就是后16个字节,魔改md5的结果.
等等,还有眼前的这83个字节转换呢!
这个是标准的RC4,先介绍下RC4
1 RC4是一种流加密算法,密钥长度可变。它加解密使用相同的密钥,因此也属于对称加密算法。
2 通过算法生成一个256字节的S-box。再通过算法每次取出S-box中的某一字节K.将K与明文做异或得到密文。
下面是我学RC4时的笔记可以参考一下,或者网上找篇文章学习下
我刚开始弄的时候没看出来RC4,虽然他一直在swap我也没想到,遇到的少,就是纯看汇编和c代码还原的,以及前面trace的文本,还原出来是查表法实现的
这里就不带大家扣了,仔细点对着汇编来还原应该都可以,我们来看看这个256字节的表是怎么来的,能否还原最初始的秘钥
在使用RC4加密时,不应使用弱密钥。当密钥长度超过128位时,至今也没有有效的破解手段,所以还是看看能不能在so里找到秘钥,硬破解不一定能弄.
sub_511E0的入参就是256字节的表,不过中间隔了3个00

0xbffff090这块内存是栈内存

pc和lr寄存器指向的都是libc,这样不太好跟,看下调用栈,断下按bt
图片不展示,敏感信息
0x04956c

v21来自51698,这个函数传了13个字节,会不会是秘钥?

扩展完和上面256字节的表对的上,这样秘钥也找到了,拿去加密验证下

验证了,是标准RC4,所有最终需要的参数就是后16字节,魔改MD5的结果
还是上面说的跟踪方法,这里不跟了,地址是0x539DC,这个函数一共跑5次,对应md5的updata函数
输出内容太多了,就展示部分,这其实是个hmac md5,hamc方法是标准的,需要结合上面hook的日志来看,我这里直接说结果了,你们自己验证下.hmac去之前ks那篇又讲或者网上找些资料.
第一次 update 64字节的0x36的扩展秘钥得到context1
第二次 update 64字节的0x5c的扩展秘钥得到context2
这两次的魔数(iv)都是
a0 = 0x10325476
b0 = 0x98badcfe
c0 = 0xefcdab89
d0 = 0x67452301
和标准的不一样
第三次 魔数用的context1,入参用的url(去掉协议和问号) + xy-common-params + xy-direction + xy-platform-info,也对应着update过程
第四次 就是第三次的填充结果的updata,不满512分组要填充,看到有0x80想到填充,得到第一个md5的结果
第五次 魔数用的context2,入参是第四次得到的md5的结果,最终加密成A9 EC EC C3 C7 90 C4 E7 78 41 37 63 F3 F5 3D AB
单看一二和三四五就发现是标准hmac
ida中c代码太长了,500行,我这里就截关键位置
1 k表
2 魔数
3 循环左移ida中的是循环右移,需要用32减去,同时循环左移的位数也改了,不是32减标准的,没规律

4 md5 64轮,每16轮算一小轮,第3小轮改了运算顺序
以下是一个标准的md5
魔改的md5
魔改点我上面说的也很清楚了,自己去还原一遍才知道md5的算法细节.
由上面的分析,最终需要逆向的参数就是hmac的秘钥

用扩展秘钥1异或0x36或秘钥2异或0x5c得到,扩展秘钥上面hook md5的代码可以得到,我没贴图.
追踪这64个字节,还是和上面一样的方法,最终生成的位置是0x52A5C

veorq_s8是两个16字节的数据逐字节异或,这里看汇编意思更清楚

异或的两个16进制来自X19和X24,hook看一下,注意这个hook需要在callinitialize这个native函数执行前调用,原因后面再说

一共6轮,看下他们异或的结果

中间0x40字节就是我们需要的,前16字节不知道是什么,最后16字节都是0x10,应该能猜出这是pkcs7填充过的吧.网上有文章说是魔改了AES,来看下findcrypt能不能找到

AES最原始的名称就是RijnDael,之前有文章介绍过这个RijnDael,这里不说了.
也就是说我们hmac的秘钥是来自中间的0x40字节,这有点奇怪啊,为什么会要填充前的0x40字节?答案就是这0x60数据是AES解密出来的,以nopadding解密出来后面会带填充的值.这样的话加密结果也是0x60字节,我们需要找到这0x60字节,这是入参

获取了
看下jni的日志,解密的上几行,获取了DeviceId和main_hmac的值,这个main_hmac值来源于文件访问,最终源头是服务器返回的,看着像是base64过的,前面有一个base64是标准的,这个应该也会是,转成16进制看看

16进制的结果是0x60个字节,这一个就是加密的数据了,可以发现前16字节和第二轮的hexString19===EE1755BFE9D97ECE5D3215AF401FA9E7对的上,后面的错开排列也对的上,这意思也很明显,上一组的密文异或一个东西得到解密的"明文",这个明文打个引号,那不就是CBC模式吗?解密出的"明文"是最初的明文异或iv得到的,最初的iv是0x3101323404020861667A666607176639,后续的iv用上一轮加密的结果,CBC模式可以防止替换某段密文来达到替换明文的效果.这里其实看汇编也能看懂
,X19是iv,X24是明文异或iv的结果,他两异或就是最原始明文
这个是AES解密,密文知道了,iv知道了,key是39923e3c-6c6e-3891-945a-fd03c4796eb3,36字节,但是AES没有36字节的key,只有16,24和32字节的,跟踪下这个key的使用,跟踪jni日志中的GetStringUtfChars,0x17d10,一路往下跟,来到秘钥编排的位置sub_51884,上面我们说hook需要在callinitialize这个native函数执行前调用,原因就是在callinitialize函数已经完成了解密,如果在最终的callintercept函数调用就好hook不上.

这里可以看到只使用了前16字节,填充方式也确认了,基本的都确认了,但是这个是魔改AES,魔改了秘钥扩展部分,改了Rcon,s盒,既然是魔改AES,听说魔改程度很大,不建议对着代码标准AES来改,因为这个AES采用的是八个大的合并表,所以直接扣代码会比跟简单些,主要就是下断,跟汇编,之前zh的x-96用的也魔改的表合并AES,那篇有讲过这么扣代码,这里我就不说了,最多花个几天时间肯定能搞定.
Java.perform(
function
(){
let xxxHttpInterceptor = Java.use(
"com.xxxxx.shield.http.xxxHttpInterceptor"
);
xxxHttpInterceptor[
"intercept"
].overload(
'okhttp3.Interceptor$Chain'
,
'long'
).implementation =
function
(chain, j2) {
var
request = chain.request();
console.log(
'1111111111111111111111:'
,j2)
var
url = request.url().toString()
console.log(
'url:'
,url)
var
headerString = request.headers().toString();
console.log(
'headers:'
,headerString)
console.log(
'1111111111111111111111'
)
let result =
this
[
"intercept"
](chain, j2);
return
result;
};
})
Java.perform(
function
(){
let xxxHttpInterceptor = Java.use(
"y62.b"
);
xxxHttpInterceptor[
"intercept"
].overload(
'okhttp3.Interceptor$Chain'
).implementation =
function
(chain) {
console.log(
'22222222222222222222222'
)
var
request = chain.request();
var
url = request.url().toString()
console.log(
'url:'
,url)
var
headerString = request.headers().toString();
console.log(
'headers:'
,headerString)
console.log(
'22222222222222222222222'
)
let result =
this
[
"intercept"
](chain);
return
result;
};
})
Java.perform(
function
(){
let xxxHttpInterceptor = Java.use(
"com.xxxxx.shield.http.xxxHttpInterceptor"
);
xxxHttpInterceptor[
"intercept"
].overload(
'okhttp3.Interceptor$Chain'
,
'long'
).implementation =
function
(chain, j2) {
var
request = chain.request();
console.log(
'1111111111111111111111:'
,j2)
var
url = request.url().toString()
console.log(
'url:'
,url)
var
headerString = request.headers().toString();
console.log(
'headers:'
,headerString)
console.log(
'1111111111111111111111'
)
let result =
this
[
"intercept"
](chain, j2);
return
result;
};
})
Java.perform(
function
(){
let xxxHttpInterceptor = Java.use(
"y62.b"
);
xxxHttpInterceptor[
"intercept"
].overload(
'okhttp3.Interceptor$Chain'
).implementation =
function
(chain) {
console.log(
'22222222222222222222222'
)
var
request = chain.request();
var
url = request.url().toString()
console.log(
'url:'
,url)
var
headerString = request.headers().toString();
console.log(
'headers:'
,headerString)
console.log(
'22222222222222222222222'
)
let result =
this
[
"intercept"
](chain);
return
result;
};
})
var
addrRegisterNatives =
null
;
var
symbols = Module.enumerateSymbolsSync(
"libart.so"
);
for
(
var
i = 0; i < symbols.length; i++) {
var
symbol = symbols[i];
if
(symbol.name.indexOf(
"art"
) >= 0 &&
symbol.name.indexOf(
"JNI"
) >= 0 &&
symbol.name.indexOf(
"RegisterNatives"
) >= 0 &&
symbol.name.indexOf(
"CheckJNI"
) < 0) {
addrRegisterNatives = symbol.address;
console.log(
"RegisterNatives is at "
, symbol.address, symbol.name);
break
}
}
if
(addrRegisterNatives) {
Interceptor.attach(addrRegisterNatives, {
onEnter:
function
(args) {
var
env = args[0];
var
java_class = args[1];
var
class_name = Java.vm.tryGetEnv().getClassName(java_class);
var
taget_class =
"com.xxxxx.shield.http.xxxHttpInterceptor"
;
if
(class_name === taget_class) {
console.log(
"\n[RegisterNatives] method_count:"
, args[3]);
var
methods_ptr = ptr(args[2]);
var
method_count = parseInt(args[3]);
for
(
var
i = 0; i < method_count; i++) {
var
name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
var
sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
var
fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));
var
name = Memory.readCString(name_ptr);
var
sig = Memory.readCString(sig_ptr);
var
find_module = Process.findModuleByAddress(fnPtr_ptr);
var
offset = ptr(fnPtr_ptr).sub(find_module.base);
console.log(
"name:"
, name,
"sig:"
, sig,
'module_name:'
,find_module.name ,
"offset:"
, offset);
}
}
}
});
}
var
addrRegisterNatives =
null
;
var
symbols = Module.enumerateSymbolsSync(
"libart.so"
);
for
(
var
i = 0; i < symbols.length; i++) {
var
symbol = symbols[i];
if
(symbol.name.indexOf(
"art"
) >= 0 &&
symbol.name.indexOf(
"JNI"
) >= 0 &&
symbol.name.indexOf(
"RegisterNatives"
) >= 0 &&
symbol.name.indexOf(
"CheckJNI"
) < 0) {
addrRegisterNatives = symbol.address;
console.log(
"RegisterNatives is at "
, symbol.address, symbol.name);
break
}
}
if
(addrRegisterNatives) {
Interceptor.attach(addrRegisterNatives, {
onEnter:
function
(args) {
var
env = args[0];
var
java_class = args[1];
var
class_name = Java.vm.tryGetEnv().getClassName(java_class);
var
taget_class =
"com.xxxxx.shield.http.xxxHttpInterceptor"
;
if
(class_name === taget_class) {
console.log(
"\n[RegisterNatives] method_count:"
, args[3]);
var
methods_ptr = ptr(args[2]);
var
method_count = parseInt(args[3]);
for
(
var
i = 0; i < method_count; i++) {
var
name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3));
var
sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize));
var
fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2));
var
name = Memory.readCString(name_ptr);
var
sig = Memory.readCString(sig_ptr);
var
find_module = Process.findModuleByAddress(fnPtr_ptr);
var
offset = ptr(fnPtr_ptr).sub(find_module.base);
console.log(
"name:"
, name,
"sig:"
, sig,
'module_name:'
,find_module.name ,
"offset:"
, offset);
}
}
}
});
}
name: initializeNative sig: ()V module_name: libxyass.so offset:
0xbd8bc
name: intercept sig: (Lokhttp3
/
Interceptor$Chain;J)Lokhttp3
/
Response; module_name: libxyass.so offset:
0xbc6b4
name: initialize sig: (Ljava
/
lang
/
String;)J module_name: libxyass.so offset:
0xbc3c8
name: destroy sig: (J)V module_name: libxyass.so offset:
0xbc380
name: initializeNative sig: ()V module_name: libxyass.so offset:
0xbd8bc
name: intercept sig: (Lokhttp3
/
Interceptor$Chain;J)Lokhttp3
/
Response; module_name: libxyass.so offset:
0xbc6b4
name: initialize sig: (Ljava
/
lang
/
String;)J module_name: libxyass.so offset:
0xbc3c8
name: destroy sig: (J)V module_name: libxyass.so offset:
0xbc380
代码不公开
String traceFile =
"unidbg-android/src/test/java/com/xxx/trace/trace2.txt"
;
PrintStream traceStream =
null
;
try
{
traceStream =
new
PrintStream(
new
FileOutputStream(traceFile),
true
);
}
catch
(FileNotFoundException e) {
e.printStackTrace();
}
emulator.traceCode(
0x40000000
,
0x40000000
+
1245184
).setRedirect(traceStream);
String traceFile =
"unidbg-android/src/test/java/com/xxx/trace/trace2.txt"
;
PrintStream traceStream =
null
;
try
{
traceStream =
new
PrintStream(
new
FileOutputStream(traceFile),
true
);
}
catch
(FileNotFoundException e) {
e.printStackTrace();
}
emulator.traceCode(
0x40000000
,
0x40000000
+
1245184
).setRedirect(traceStream);
public
void
HookByConsoleDebugger() {
Debugger debugger = emulator.attach();
debugger.addBreakPoint(module.base+
0xBCF2C
);
}
public
void
HookByConsoleDebugger() {
Debugger debugger = emulator.attach();
debugger.addBreakPoint(module.base+
0xBCF2C
);
}
emulator.traceWrite(
0x40461018
,
0x40461018
+
134
);
emulator.traceWrite(
0x40461018
,
0x40461018
+
134
);
emulator.traceWrite(
0x4058e024
,
0x4058e024
+
9
);
emulator.traceWrite(
0x4058e024
,
0x4058e024
+
9
);
总结
通过算法生成一个256字节的S-box。
再通过算法每次取出S-box中的某一字节K.
将K与明文做异或得到密文。
重点是打乱的s盒
1、先初始化状态向量S(256个字节,用来作为密钥流生成的种子1)
按照升序,给每个字节赋值0,1,2,3,4,5,6.....,254,255
2、初始密钥(由用户输入),长度任意
如果输入长度小于256个字节,则进行轮转,直到填满
例如输入密钥的是1,2,3,4,5 , 那么填入的是1,2,3,4,5,1,2,3,4,5,1,2,3,4,5........
3、开始对状态向量S进行置换操作(用来打乱初始种子1)
j = 0;
for (i = 0 ; i < 256 ; i++){
j = (j + S[i] + T[i]) % 256;
swap(S[i] , S[j]);
}
4、最后是秘钥流的生成与加密,很多人在这里不是特别理解
假设我的明文字节数是datalength=1024个字节(当然可以是任意个字节)
i=0;
j=0;
while(datalength--){//相当于执行1024次,这样生成的秘钥流也是1024个字节
i = (i + 1) % 256;
j = (j + S[i]) % 256;
swap(S[i] , S[j]);
t = (S[i] + S[j]) % 256;
k = S[t];这里的K就是当前生成的一个秘钥流中的一位
//可以直接在这里进行加密,当然也可以将密钥流保存在数组中,最后进行异或就ok
data[]=data[]^k; //进行加密,"^"是异或运算符
}
解密按照前面写的,异或两次就是原文,所以只要把密钥流重新拿过来异或一次就能得到原文了
这样就完成了一次生成密钥流及加密的过程,这也是RC4的全部工作,是不是很简单呢?
总结
通过算法生成一个256字节的S-box。
再通过算法每次取出S-box中的某一字节K.
将K与明文做异或得到密文。
重点是打乱的s盒
1、先初始化状态向量S(256个字节,用来作为密钥流生成的种子1)
按照升序,给每个字节赋值0,1,2,3,4,5,6.....,254,255
2、初始密钥(由用户输入),长度任意
如果输入长度小于256个字节,则进行轮转,直到填满
例如输入密钥的是1,2,3,4,5 , 那么填入的是1,2,3,4,5,1,2,3,4,5,1,2,3,4,5........
3、开始对状态向量S进行置换操作(用来打乱初始种子1)
j = 0;
for (i = 0 ; i < 256 ; i++){
j = (j + S[i] + T[i]) % 256;
swap(S[i] , S[j]);
}
4、最后是秘钥流的生成与加密,很多人在这里不是特别理解
假设我的明文字节数是datalength=1024个字节(当然可以是任意个字节)
i=0;
j=0;
while(datalength--){//相当于执行1024次,这样生成的秘钥流也是1024个字节
i = (i + 1) % 256;
j = (j + S[i]) % 256;
swap(S[i] , S[j]);
t = (S[i] + S[j]) % 256;
k = S[t];这里的K就是当前生成的一个秘钥流中的一位
//可以直接在这里进行加密,当然也可以将密钥流保存在数组中,最后进行异或就ok
data[]=data[]^k; //进行加密,"^"是异或运算符
}
解密按照前面写的,异或两次就是原文,所以只要把密钥流重新拿过来异或一次就能得到原文了
这样就完成了一次生成密钥流及加密的过程,这也是RC4的全部工作,是不是很简单呢?
def
swap(
list
, swap1, swap2):
int1
=
list
.index(swap1)
int2
=
list
.index(swap2)
list
[int1],
list
[int2]
=
list
[int2],
list
[int1]
return
list
def
eightyRounds(i, result1,
next
, _str, a3):
for
j
in
range
(
8
):
mid
=
result1[i
*
8
+
j
+
1
]
_swap
=
result1[(mid
+
next
) &
0xff
]
result1
=
swap(result1, mid, _swap)
res
=
a3[i
*
8
+
j] ^ result1[(_swap
+
mid) &
0xff
]
_str
+
=
hex
(res)[
2
:]
if
len
(
hex
(res)[
2
:])
=
=
2
else
'0'
+
hex
(res)[
2
:]
next
=
(mid
+
next
) &
0xff
return
result1,
next
, _str
result1
=
[
0x7c
,
0x2e
,
0x0e
,
0x3d
,
0x09
,
0x32
,
0xe3
,
0x1c
,
0x87
,
0xc9
,
0xb3
,
0x2d
,
0xb1
,
0x2b
,
0xdd
,
0x20
,
0x0b
,
0xc3
,
0x28
,
0x5c
,
0x0f
,
0x7b
,
0x12
,
0x53
,
0x0c
,
0x2f
,
0x92
,
0x23
,
0x30
,
0xce
,
0x50
,
0xd0
,
0x40
,
0x1f
,
0x45
,
0x33
,
0x3b
,
0x95
,
0xb2
,
0x15
,
0xbc
,
0x34
,
0x89
,
0xe6
,
0xd5
,
0x39
,
0x68
,
0x78
,
0xf1
,
0x80
,
0x7f
,
0xc1
,
0xca
,
0x3e
,
0x71
,
0x52
,
0x7a
,
0x5e
,
0xe7
,
0xa4
,
0x37
,
0xa5
,
0x69
,
0xd1
,
0x4c
,
0x73
,
0xb6
,
0x5b
,
0xfe
,
0x16
,
0xcf
,
0x55
,
0xcb
,
0xc0
,
0xf9
,
0x24
,
0x10
,
0xa8
,
0x6b
,
0xe0
,
0x62
,
0x8c
,
0x63
,
0xd9
,
0xbd
,
0xda
,
0x31
,
0xf3
,
0x96
,
0xe4
,
0x75
,
0x5d
,
0xf7
,
0x79
,
0x22
,
0x57
,
0xde
,
0xbf
,
0x91
,
0x86
,
0xea
,
0x85
,
0x97
,
0x4d
,
0x83
,
0x00
,
0xa9
,
0x84
,
0x14
,
0x27
,
0x1a
,
0x17
,
0xed
,
0xe1
,
0x1b
,
0x6f
,
0x41
,
0x59
,
0xa2
,
0x99
,
0xfc
,
0x4b
,
0x1e
,
0xa7
,
0x74
,
0xab
,
0x7d
,
0x88
,
0x5a
,
0x51
,
0xe2
,
0xbe
,
0xa6
,
0x77
,
0x67
,
0x58
,
0x11
,
0x0d
,
0xa0
,
0x8f
,
0x08
,
0x2a
,
0x72
,
0xd2
,
0xc2
,
0x9b
,
0x36
,
0xd7
,
0xf2
,
0x70
,
0x35
,
0x8e
,
0xd3
,
0x03
,
0xb7
,
0xb9
,
0xc8
,
0x2c
,
0x93
,
0xb0
,
0xee
,
0x8d
,
0x07
,
0xf8
,
0x47
,
0x8b
,
0xe9
,
0x90
,
0x04
,
0x46
,
0x94
,
0xd4
,
0x49
,
0x4e
,
0xb5
,
0xd6
,
0xa1
,
0xac
,
0x4f
,
0xbb
,
0xdc
,
0xff
,
0x18
,
0xba
,
0xaf
,
0xc4
,
0x26
,
0x6e
,
0x9e
,
0x6d
,
0x3a
,
0x5f
,
0xc7
,
0x82
,
0x44
,
0xae
,
0xcd
,
0x8a
,
0xad
,
0x3c
,
0x38
,
0x01
,
0xa3
,
0xdf
,
0xc5
,
0x05
,
0x02
,
0xf4
,
0xf0
,
0x06
,
0x13
,
0x3f
,
0xef
,
0x29
,
0x64
,
0xfd
,
0x66
,
0x25
,
0x60
,
0xeb
,
0xe8
,
0x61
,
0x7e
,
0xfa
,
0x54
,
0x9a
,
0xfb
,
0xd8
,
0xf5
,
0xb4
,
0x48
,
0x76
,
0x43
,
0x65
,
0x6a
,
0xec
,
0x9c
,
0x1d
,
0xf6
,
0x0a
,
0xe5
,
0x9f
,
0x42
,
0x6c
,
0xc6
,
0xb8
,
0xcc
,
0x9d
,
0xaa
,
0xdb
,
0x98
,
0x21
,
0x81
,
0x56
,
0x4a
,
0x19
]
next
=
0
_str
=
''
a3
=
[
0x00
,
0x00
,
0x00
,
0x01
,
0xec
,
0xfa
,
0xaf
,
0x01
,
0x00
,
0x00
,
0x00
,
0x02
,
0x00
,
0x00
,
0x00
,
0x07
,
0x00
,
0x00
,
0x00
,
0x24
,
0x00
,
0x00
,
0x00
,
0x10
,
0x38
,
0x33
,
0x32
,
0x30
,
0x36
,
0x38
,
0x39
,
0x33
,
0x39
,
0x39
,
0x32
,
0x33
,
0x65
,
0x33
,
0x63
,
0x2d
,
0x36
,
0x63
,
0x36
,
0x65
,
0x2d
,
0x33
,
0x38
,
0x39
,
0x31
,
0x2d
,
0x39
,
0x34
,
0x35
,
0x61
,
0x2d
,
0x66
,
0x64
,
0x30
,
0x33
,
0x63
,
0x34
,
0x37
,
0x39
,
0x36
,
0x65
,
0x62
,
0x33
,
0xa9
,
0xec
,
0xec
,
0xc3
,
0xc7
,
0x90
,
0xc4
,
0xe7
,
0x78
,
0x41
,
0x37
,
0x63
,
0xf3
,
0xf5
,
0x3d
,
0xab
]
for
i
in
range
(
10
):
result1,
next
, _str
=
eightyRounds(i, result1,
next
, _str, a3)
byte1
=
a3[
80
] ^ result1[(result1[
0x51
]
+
result1[(result1[
0x51
]
+
next
) &
0xff
]) &
0xff
]
next
=
result1[
0x51
]
+
next
_str
+
=
hex
(byte1)[
2
:]
if
len
(
hex
(byte1)[
2
:])
=
=
2
else
'0'
+
hex
(byte1)[
2
:]
result1
=
swap(result1, result1[
0x51
], result1[(result1[
0x51
]
+
next
) &
0xff
])
byte2
=
a3[
81
] ^ result1[(result1[
0x52
]
+
result1[(result1[
0x52
]
+
next
) &
0xff
]) &
0xff
]
next
=
result1[
0x52
]
+
next
_str
+
=
hex
(byte2)[
2
:]
if
len
(
hex
(byte2)[
2
:])
=
=
2
else
'0'
+
hex
(byte2)[
2
:]
result1
=
swap(result1, result1[
0x52
], result1[(result1[
0x52
]
+
next
) &
0xff
])
byte2
=
a3[
82
] ^ result1[(result1[
0x53
]
+
result1[(result1[
0x53
]
+
next
) &
0xff
]) &
0xff
]
_str
+
=
hex
(byte2)[
2
:]
if
len
(
hex
(byte2)[
2
:])
=
=
2
else
'0'
+
hex
(byte2)[
2
:]
print
(_str)
def
swap(
list
, swap1, swap2):
int1
=
list
.index(swap1)
int2
=
list
.index(swap2)
list
[int1],
list
[int2]
=
list
[int2],
list
[int1]
return
list
def
eightyRounds(i, result1,
next
, _str, a3):
for
j
in
range
(
8
):
mid
=
result1[i
*
8
+
j
+
1
]
_swap
=
result1[(mid
+
next
) &
0xff
]
result1
=
swap(result1, mid, _swap)
res
=
a3[i
*
8
+
j] ^ result1[(_swap
+
mid) &
0xff
]
_str
+
=
hex
(res)[
2
:]
if
len
(
hex
(res)[
2
:])
=
=
2
else
'0'
+
hex
(res)[
2
:]
next
=
(mid
+
next
) &
0xff
return
result1,
next
, _str
result1
=
[
0x7c
,
0x2e
,
0x0e
,
0x3d
,
0x09
,
0x32
,
0xe3
,
0x1c
,
0x87
,
0xc9
,
0xb3
,
0x2d
,
0xb1
,
0x2b
,
0xdd
,
0x20
,
0x0b
,
0xc3
,
0x28
,
0x5c
,
0x0f
,
0x7b
,
0x12
,
0x53
,
0x0c
,
0x2f
,
0x92
,
0x23
,
0x30
,
0xce
,
0x50
,
0xd0
,
0x40
,
0x1f
,
0x45
,
0x33
,
0x3b
,
0x95
,
0xb2
,
0x15
,
0xbc
,
0x34
,
0x89
,
0xe6
,
0xd5
,
0x39
,
0x68
,
0x78
,
0xf1
,
0x80
,
0x7f
,
0xc1
,
0xca
,
0x3e
,
0x71
,
0x52
,
0x7a
,
0x5e
,
0xe7
,
0xa4
,
0x37
,
0xa5
,
0x69
,
0xd1
,
0x4c
,
0x73
,
0xb6
,
0x5b
,
0xfe
,
0x16
,
0xcf
,
0x55
,
0xcb
,
0xc0
,
0xf9
,
0x24
,
0x10
,
0xa8
,
0x6b
,
0xe0
,
0x62
,
0x8c
,
0x63
,
0xd9
,
0xbd
,
0xda
,
0x31
,
0xf3
,
0x96
,
0xe4
,
0x75
,
0x5d
,
0xf7
,
0x79
,
0x22
,
0x57
,
0xde
,
0xbf
,
0x91
,
0x86
,
0xea
,
0x85
,
0x97
,
0x4d
,
0x83
,
0x00
,
0xa9
,
0x84
,
0x14
,
0x27
,
0x1a
,
0x17
,
0xed
,
0xe1
,
0x1b
,
0x6f
,
0x41
,
0x59
,
0xa2
,
0x99
,
0xfc
,
0x4b
,
0x1e
,
0xa7
,
0x74
,
0xab
,
0x7d
,
0x88
,
0x5a
,
0x51
,
0xe2
,
0xbe
,
0xa6
,
0x77
,
0x67
,
0x58
,
0x11
,
0x0d
,
0xa0
,
0x8f
,
0x08
,
0x2a
,
0x72
,
0xd2
,
0xc2
,
0x9b
,
0x36
,
0xd7
,
0xf2
,
0x70
,
0x35
,
0x8e
,
0xd3
,
0x03
,
0xb7
,
0xb9
,
0xc8
,
0x2c
,
0x93
,
0xb0
,
0xee
,
0x8d
,
0x07
,
0xf8
,
0x47
,
0x8b
,
0xe9
,
0x90
,
0x04
,
0x46
,
0x94
,
0xd4
,
0x49
,
0x4e
,
0xb5
,
0xd6
,
0xa1
,
0xac
,
0x4f
,
0xbb
,
0xdc
,
0xff
,
0x18
,
0xba
,
0xaf
,
0xc4
,
0x26
,
0x6e
,
0x9e
,
0x6d
,
0x3a
,
0x5f
,
0xc7
,
0x82
,
0x44
,
0xae
,
0xcd
,
0x8a
,
0xad
,
0x3c
,
0x38
,
0x01
,
0xa3
,
0xdf
,
0xc5
,
0x05
,
0x02
,
0xf4
,
0xf0
,
0x06
,
0x13
,
0x3f
,
0xef
,
0x29
,
0x64
,
0xfd
,
0x66
,
0x25
,
0x60
,
0xeb
,
0xe8
,
0x61
,
0x7e
,
0xfa
,
0x54
,
0x9a
,
0xfb
,
0xd8
,
0xf5
,
0xb4
,
0x48
,
0x76
,
0x43
,
0x65
,
0x6a
,
0xec
,
0x9c
,
0x1d
,
0xf6
,
0x0a
,
0xe5
,
0x9f
,
0x42
,
0x6c
,
0xc6
,
0xb8
,
0xcc
,
0x9d
,
0xaa
,
0xdb
,
0x98
,
0x21
,
0x81
,
0x56
,
0x4a
,
0x19
]
next
=
0
_str
=
''
a3
=
[
0x00
,
0x00
,
0x00
,
0x01
,
0xec
,
0xfa
,
0xaf
,
0x01
,
0x00
,
0x00
,
0x00
,
0x02
,
0x00
,
0x00
,
0x00
,
0x07
,
0x00
,
0x00
,
0x00
,
0x24
,
0x00
,
0x00
,
0x00
,
0x10
,
0x38
,
0x33
,
0x32
,
0x30
,
0x36
,
0x38
,
0x39
,
0x33
,
0x39
,
0x39
,
0x32
,
0x33
,
0x65
,
0x33
,
0x63
,
0x2d
,
0x36
,
0x63
,
0x36
,
0x65
,
0x2d
,
0x33
,
0x38
,
0x39
,
0x31
,
0x2d
,
0x39
,
0x34
,
0x35
,
0x61
,
0x2d
,
0x66
,
0x64
,
0x30
,
0x33
,
0x63
,
0x34
,
0x37
,
0x39
,
0x36
,
0x65
,
0x62
,
0x33
,
0xa9
,
0xec
,
0xec
,
0xc3
,
0xc7
,
0x90
,
0xc4
,
0xe7
,
0x78
,
0x41
,
0x37
,
0x63
,
0xf3
,
0xf5
,
0x3d
,
0xab
]
for
i
in
range
(
10
):
result1,
next
, _str
=
eightyRounds(i, result1,
next
, _str, a3)
byte1
=
a3[
80
] ^ result1[(result1[
0x51
]
+
result1[(result1[
0x51
]
+
next
) &
0xff
]) &
0xff
]
next
=
result1[
0x51
]
+
next
_str
+
=
hex
(byte1)[
2
:]
if
len
(
hex
(byte1)[
2
:])
=
=
2
else
'0'
+
hex
(byte1)[
2
:]
result1
=
swap(result1, result1[
0x51
], result1[(result1[
0x51
]
+
next
) &
0xff
])
byte2
=
a3[
81
] ^ result1[(result1[
0x52
]
+
result1[(result1[
0x52
]
+
next
) &
0xff
]) &
0xff
]
next
=
result1[
0x52
]
+
next
_str
+
=
hex
(byte2)[
2
:]
if
len
(
hex
(byte2)[
2
:])
=
=
2
else
'0'
+
hex
(byte2)[
2
:]
result1
=
swap(result1, result1[
0x52
], result1[(result1[
0x52
]
+
next
) &
0xff
])
byte2
=
a3[
82
] ^ result1[(result1[
0x53
]
+
result1[(result1[
0x53
]
+
next
) &
0xff
]) &
0xff
]
_str
+
=
hex
(byte2)[
2
:]
if
len
(
hex
(byte2)[
2
:])
=
=
2
else
'0'
+
hex
(byte2)[
2
:]
print
(_str)
[培训]科锐逆向工程师培训第53期2025年7月8日开班!
最后于 2024-5-25 09:54
被杨如画编辑
,原因: 更正