-
-
[原创][SHCTF]easyLogin 出题小记
-
发表于: 2025-1-10 12:42 2275
-
改机APP直接改,梭哈。
直接看主体逻辑,其实就是发送了Username以及password还有passticket,username和password都给我们了,但是passticket并没有给我们,因此需要去逆向,首先根据下面Toast的代码告诉了我们这个可能和设备有关,这个时候需要考虑的验证是否新设备是否使用到设备id之类的。
getPassticket注册于easyLogin,那么我们需要使用IDA直接分析easyLogin。
这里我的设备为Arm64 因此我分析的为arm64-v8a,(注意不同设备接下来的操作可能不尽相同,但是原理逻辑基本一致)
函数列表中没有发现Jni_Onload,可以确定为静态注册,静态注册直接搜索函数名字就好了:
这里需要注意参数类型变换,可能需要手动更改:
可以发现这里有输出Device ID的字样。
那么根据提示,我们的主要目标就是替换掉这个device id。
查看一下数据包:
可以发现passticket上传的并不是设备id,二十哈希之后的设备id,并且显然不是md5值。
这个时候要么分析这个passticket 要么 复现这个哈希算法。
看到这里基本也不会有想去逆向哈希算法的思路了。
只有调试或者FridaHook了。
但是程序存在hook检测
主要看init Array段中的一些内容:
创建了两个线程
检测IDA的我们不用看,直接撸检测frida的:
比较了本地和系统的libc中 signal 的前8个字符是否一致,不一致则认为被hook,这里hook点可以在v13==v12
修改他们的比较结果即可,这里值的注意的是由于时机问题可以直接hook pthread_create来hook这个点位
或者重定向fread:
最后我们的脚本还需要注意时机,这里给出完整的重定向的代码:
本题没有标准解,师傅们可以打开思维,需求更多的破解方式,体会Re的乐趣。
function
passAnti1() {
Interceptor.attach(Module.getExportByName(
null
,
"pthread_create"
), {
onEnter:
function
(args) {
this
.funAddr = args[2];
var
instruction = Instruction.parse(
this
.funAddr.add(0x2b4));
if
(instruction.mnemonic ===
"cmp"
) {
Interceptor.attach(
this
.funAddr.add(0x2b4), {
onEnter:
function
(args) {
this
.context.x25 =
this
.context.x24;
}
});
}
},
onLeave:
function
(retval) {
console.log(
"pthread_create returned"
);
}
});
}
function
passAnti1() {
Interceptor.attach(Module.getExportByName(
null
,
"pthread_create"
), {
onEnter:
function
(args) {
this
.funAddr = args[2];
var
instruction = Instruction.parse(
this
.funAddr.add(0x2b4));
if
(instruction.mnemonic ===
"cmp"
) {
Interceptor.attach(
this
.funAddr.add(0x2b4), {
onEnter:
function
(args) {
this
.context.x25 =
this
.context.x24;
}
});
}
},
onLeave:
function
(retval) {
console.log(
"pthread_create returned"
);
}
});
}
function
hook_memcmp_addr() {
//hook反调试
var
memcmp_addr = Module.findExportByName(
"libc.so"
,
"fread"
);
if
(memcmp_addr !==
null
) {
// console.log("fread address: ", memcmp_addr);
Interceptor.attach(memcmp_addr, {
onEnter:
function
(args) {
this
.buffer = args[0];
// 保存 buffer 参数
this
.size = args[1];
// 保存 size 参数
this
.count = args[2];
// 保存 count 参数
this
.stream = args[3];
// 保存 FILE* 参数
},
onLeave:
function
(retval) {
// console.log(this.count.toInt32());
if
(
this
.count.toInt32() == 8) {
Memory.writeByteArray(
this
.buffer, [0x50, 0x00, 0x00, 0x58, 0x00, 0x02, 0x1f, 0xd6]);
retval.replace(8);
// 填充前8字节
// console.log(hexdump(this.buffer));
}
}
});
}
else
{
console.log(
"Error: memcmp function not found in libc.so"
);
}
}
function
hook_memcmp_addr() {
//hook反调试
var
memcmp_addr = Module.findExportByName(
"libc.so"
,
"fread"
);
if
(memcmp_addr !==
null
) {
// console.log("fread address: ", memcmp_addr);
Interceptor.attach(memcmp_addr, {
onEnter:
function
(args) {
this
.buffer = args[0];
// 保存 buffer 参数
this
.size = args[1];
// 保存 size 参数
this
.count = args[2];
// 保存 count 参数
this
.stream = args[3];
// 保存 FILE* 参数
},
onLeave:
function
(retval) {
// console.log(this.count.toInt32());
if
(
this
.count.toInt32() == 8) {
Memory.writeByteArray(
this
.buffer, [0x50, 0x00, 0x00, 0x58, 0x00, 0x02, 0x1f, 0xd6]);
retval.replace(8);
// 填充前8字节
// console.log(hexdump(this.buffer));
}
}
});
}
else
{
console.log(
"Error: memcmp function not found in libc.so"
);
}
}
function
hook_memcmp_addr() {
var
memcmp_addr = Module.findExportByName(
"libc.so"
,
"fread"
);
if
(memcmp_addr !==
null
) {
Interceptor.attach(memcmp_addr, {
onEnter:
function
(args) {
this
.buffer = args[0];
this
.size = args[1];
this
.count = args[2];
this
.stream = args[3];
},
onLeave:
function
(retval) {
if
(
this
.count.toInt32() == 8) {
Memory.writeByteArray(
this
.buffer, [0x50, 0x00, 0x00, 0x58, 0x00, 0x02, 0x1f, 0xd6]);
retval.replace(8);
}
}
});
}
else
{
console.log(
"Error: memcmp function not found in libc.so"
);
}
}
function
NativeHook() {
var
base = Module.getBaseAddress(
"libeasylogin.so"
);
console.log(
"[Base]->"
, base);
Interceptor.attach(base.add(0x1F250), {
onEnter:
function
(args) {
try
{
var
originalStr =
this
.context.x0.readCString();
console.log(
"Original x0:"
, originalStr);
var
newValue =
"a24256ec5983b4a8"
;
if
(newValue.length <= originalStr.length) {
Memory.writeUtf8String(
this
.context.x0, newValue);
console.log(
"Modified x0:"
,
this
.context.x0.readCString());
}
else
{
console.warn(
"New string is longer than the original. Skipping write to avoid overflow."
);
}
}
catch
(e) {
console.error(
"Error modifying x0 content:"
, e);
}
}
});
}
function
Hookdlopenext() {
hook_memcmp_addr();
var
dlopen = Module.findExportByName(
null
,
"android_dlopen_ext"
);
Interceptor.attach(dlopen, {
onEnter:
function
(args) {
var
filePath = args[0].readCString();
console.log(
"[android_dlopen_ext] -> "
, filePath);
if
(filePath.indexOf(
"libeasylogin"
) != -1) {
this
.isCanHook =
true
;
}
}, onLeave:
function
(retValue) {
if
(
this
.isCanHook) {
this
.isCanHook =
false
;
NativeHook();
}
}
})
}
setImmediate(Hookdlopenext);
function
hook_memcmp_addr() {
var
memcmp_addr = Module.findExportByName(
"libc.so"
,
"fread"
);
if
(memcmp_addr !==
null
) {
Interceptor.attach(memcmp_addr, {
onEnter:
function
(args) {
this
.buffer = args[0];
this
.size = args[1];
this
.count = args[2];
[招生]系统0day安全班,企业级设备固件漏洞挖掘,Linux平台漏洞挖掘!