(本文是针对U3D编译为libil2cpp的情况做分析)
导出到文本里就可以快速找到实际运行时候的地址以及ida里面分析的地址
(emmm 其实也不是不行,咋们的frida也是提供了本地hook的能力的,只是这里咋们考虑使用dobby进行hook,还有就是js在这里使用不是很方便文件操作,实现通用化的汉化模式,测试学习玩玩还是可以的 所以 嗯...,具体怎么用frida本地hook,参考我的另一篇文章---> 见文章底部)
其实这里还有问题没考虑到(随便举例一个):
大概就这意思,平时空余时间写的demo,欢迎大佬来fork修改提交共同完善这个小工具,这里不适合贴太多代码,详细代码移步
UnityGameLocalizationDemo
const
-
string v1,
"inject"
invoke
-
static {v1}, Ljava
/
lang
/
System;
-
>loadLibrary(Ljava
/
lang
/
String;)V
const
-
string v1,
"inject"
invoke
-
static {v1}, Ljava
/
lang
/
System;
-
>loadLibrary(Ljava
/
lang
/
String;)V
/
/
运行以下脚本输出日志到文本
frida
-
U
-
f <pkgName>
-
l hook.js
-
-
no
-
pause
-
o c:\temp.txt
function hook(){
var p_size
=
Process.pointerSize
var soAddr
=
Module.findBaseAddress(
"libil2cpp.so"
)
Interceptor.attach(Module.findExportByName(
"libil2cpp.so"
,
"il2cpp_class_get_methods"
),{
onEnter:function(args){
},
onLeave:function(ret){
console.error(
"--------------------------------------------------------"
)
console.log(hexdump(ret,{length:
16
}))
console.log(
"methodPointer => \t"
+
ret.readPointer()
+
"\t ===> \t"
+
ret.readPointer().sub(soAddr))
console.log(
"invoker_method => \t"
+
ret.add(p_size
*
1
).readPointer()
+
"\t ===> \t"
+
ret.add(p_size
*
1
).readPointer().sub(soAddr))
console.log(
"MethodName => \t\t"
+
ret.add(p_size
*
2
).readPointer().readCString())
var klass
=
ret.add(p_size
*
3
).readPointer()
console.log(
"namespaze => \t\t"
+
klass.add(p_size
*
3
).readPointer().readCString()
+
"."
+
klass.add(p_size
*
2
).readPointer().readCString())
}
})
}
/
/
运行以下脚本输出日志到文本
frida
-
U
-
f <pkgName>
-
l hook.js
-
-
no
-
pause
-
o c:\temp.txt
function hook(){
var p_size
=
Process.pointerSize
var soAddr
=
Module.findBaseAddress(
"libil2cpp.so"
)
Interceptor.attach(Module.findExportByName(
"libil2cpp.so"
,
"il2cpp_class_get_methods"
),{
onEnter:function(args){
},
onLeave:function(ret){
console.error(
"--------------------------------------------------------"
)
console.log(hexdump(ret,{length:
16
}))
console.log(
"methodPointer => \t"
+
ret.readPointer()
+
"\t ===> \t"
+
ret.readPointer().sub(soAddr))
console.log(
"invoker_method => \t"
+
ret.add(p_size
*
1
).readPointer()
+
"\t ===> \t"
+
ret.add(p_size
*
1
).readPointer().sub(soAddr))
console.log(
"MethodName => \t\t"
+
ret.add(p_size
*
2
).readPointer().readCString())
var klass
=
ret.add(p_size
*
3
).readPointer()
console.log(
"namespaze => \t\t"
+
klass.add(p_size
*
3
).readPointer().readCString()
+
"."
+
klass.add(p_size
*
2
).readPointer().readCString())
}
})
}
void
*
new_func_set(void
*
arg, void
*
arg1, void
*
arg2, void
*
arg3) {
LOGD(
"Enter new_func_set %d"
,current_get_index);
current_set_index
+
+
;
/
/
set
的时候第二个参数可能为
0
,就像get的时候返回值可能为
0
一样
if
(arg1
=
=
0
)
return
old_func_set(arg, arg1, arg2, arg3);
try
{
memset(header_set,
0
, HeaderSize);
memcpy(header_set, arg1, HeaderSize);
memset(end,
0
, EndSize);
memset(middle_set,
0
, SplitSize);
/
/
以八个
0
作为结束,拷贝以返回值偏移
12
个字节的作为开始的内存数据,其实就是中间文字部分
memccpy(middle_set, (char
*
) arg1
+
sizeof(char)
*
HeaderSize, reinterpret_cast<
int
>(end), SplitSize);
void
*
p_le
=
memchr(middle_set,reinterpret_cast<
int
>(end),SplitSize);
/
/
原返回值中间文字部分的长度
int
src_length
=
(char
*
)p_le
-
(char
*
)middle_set;
int
current_lines
=
0
;
/
/
初始化解析文本以“|”作为分割左边 右边部分缓存指针
char
*
left
=
static_cast<char
*
>(calloc(SplitSize, sizeof(char)));
char
*
right
=
static_cast<char
*
>(calloc(SplitSize, sizeof(char)));
/
/
读取文件后删除了源文件的,从这里的
buffer
拷贝一个备份来操作
char
*
temp_buffer
=
(char
*
) malloc(sizeof(char)
*
file_size
+
sizeof(
int
));
memcpy(temp_buffer,
buffer
, sizeof(char)
*
file_size
+
sizeof(
int
));
char
*
p
=
strtok(temp_buffer,
"\r\n"
);
while
(p !
=
NULL) {
memset(left,
0
, SplitSize);
memset(right,
0
, SplitSize);
char
*
s
=
strstr(p,
"|"
);
static_cast<char
*
>(memcpy(left, p, strlen(p)
-
strlen(s)));
right
=
strcpy(right, s
+
sizeof(char));
if
(current_lines !
=
0
) {
char
*
convert_str
=
static_cast<char
*
>(malloc(strlen(left)
*
2
));
memset(convert_str,
0
, strlen(left)
*
2
);
int
length
=
UTF8_to_Unicode(convert_str, left);
/
/
length
=
=
(src_length
-
EndSize) &&
/
/
LOGD(
"src_length - EndSize %d"
, src_length
-
EndSize);
/
/
内存字节的比较
if
(memcmp(middle_set, convert_str, src_length
-
EndSize)
=
=
0
) {
LOGE(
"---> called set_text replace %s to %s times:%d"
,left,right,current_set_index);
LOGD(
"Original str hex at %p === >"
,&middle_set);
hexDump(reinterpret_cast<const char
*
>(middle_set), src_length);
void
*
p
=
malloc(strlen(right)
*
2
);
int
le
=
UTF8_to_Unicode(static_cast<char
*
>(p), right);
LOGD(
"Replacement str hex at %p === >"
,&le);
hexDump(reinterpret_cast<const char
*
>(p), le);
/
/
申请空间来重新组合返回值
void
*
temp
=
malloc(static_cast<size_t>(HeaderSize
+
le
+
EndSize));
memset(temp,
0
, static_cast<size_t>(HeaderSize
+
le
+
EndSize));
memcpy(temp, header_set, HeaderSize);
memcpy((char
*
) temp
+
HeaderSize, p, static_cast<size_t>(le));
memcpy((char
*
) temp
+
HeaderSize
+
le, end, EndSize);
LOGD(
"Return str hex at %p === >"
,&temp);
hexDump(static_cast<const char
*
>(temp), static_cast<size_t>(HeaderSize
+
le
+
EndSize));
free(convert_str);
free(left);
free(right);
free(temp_buffer);
return
old_func_set(arg, temp, arg2, arg3);
}
}
p
=
strtok(NULL,
"\r\n"
);
current_lines
+
+
;
}
free(left);
free(right);
free(temp_buffer);
return
old_func_set(arg, arg1, arg2, arg3);
}catch (...){
LOGE(
"ERRR MENORY"
);
return
old_func_set(arg, arg1, arg2, arg3);
}
}
void
*
new_func_set(void
*
arg, void
*
arg1, void
*
arg2, void
*
arg3) {
LOGD(
"Enter new_func_set %d"
,current_get_index);
current_set_index
+
+
;
/
/
set
的时候第二个参数可能为
0
,就像get的时候返回值可能为
0
一样
if
(arg1
=
=
0
)
return
old_func_set(arg, arg1, arg2, arg3);
try
{
memset(header_set,
0
, HeaderSize);
memcpy(header_set, arg1, HeaderSize);
memset(end,
0
, EndSize);
memset(middle_set,
0
, SplitSize);
/
/
以八个
0
作为结束,拷贝以返回值偏移
12
个字节的作为开始的内存数据,其实就是中间文字部分
memccpy(middle_set, (char
*
) arg1
+
sizeof(char)
*
HeaderSize, reinterpret_cast<
int
>(end), SplitSize);
void
*
p_le
=
memchr(middle_set,reinterpret_cast<
int
>(end),SplitSize);
/
/
原返回值中间文字部分的长度
int
src_length
=
(char
*
)p_le
-
(char
*
)middle_set;
int
current_lines
=
0
;
/
/
初始化解析文本以“|”作为分割左边 右边部分缓存指针
char
*
left
=
static_cast<char
*
>(calloc(SplitSize, sizeof(char)));
char
*
right
=
static_cast<char
*
>(calloc(SplitSize, sizeof(char)));
/
/
读取文件后删除了源文件的,从这里的
buffer
拷贝一个备份来操作
char
*
temp_buffer
=
(char
*
) malloc(sizeof(char)
*
file_size
+
sizeof(
int
));
memcpy(temp_buffer,
buffer
, sizeof(char)
*
file_size
+
sizeof(
int
));
char
*
p
=
strtok(temp_buffer,
"\r\n"
);
while
(p !
=
NULL) {
memset(left,
0
, SplitSize);
memset(right,
0
, SplitSize);
char
*
s
=
strstr(p,
"|"
);
static_cast<char
*
>(memcpy(left, p, strlen(p)
-
strlen(s)));
right
=
strcpy(right, s
+
sizeof(char));
if
(current_lines !
=
0
) {
char
*
convert_str
=
static_cast<char
*
>(malloc(strlen(left)
*
2
));
memset(convert_str,
0
, strlen(left)
*
2
);
int
length
=
UTF8_to_Unicode(convert_str, left);
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2020-11-24 15:37
被唱过阡陌编辑
,原因: 更新新的想法,完善文章