Linux Reverse(1)-LD_PRELOAD
LD_PRELOAD
是 Linux 系统中的一个环境变量,它允许用户在程序运行时动态地加载共享库。通过设置该环境变量,用户可以指定一个或多个共享库,这些库中的函数将在其他库或程序调用相同函数时优先使用。这在调试、注入、替换函数实现或修改程序行为时非常有用。
使用场景
-
函数替换:当你想要替换某个标准库的函数实现时,可以使用
LD_PRELOAD
来加载自定义的库。例如,如果你想要替换malloc
函数,可以编写一个动态库实现自己的malloc
,然后通过LD_PRELOAD
指定该库。 -
调试和分析:在调试程序时,使用
LD_PRELOAD
可以用来跟踪函数的调用,收集性能数据,或进行故障排查。 -
干扰特定应用程序:通过重写程序的某些功能,可以阻止特定的行为或限制程序的访问权限。
基本用法
假设你有一个动态库 mylib.so
,它包含了对某些函数的重写,你可以通过以下方式来使用 LD_PRELOAD
:
LD_PRELOAD=/path/to/mylib.so ./your_program
这里的 /path/to/mylib.so
是你自定义的动态库的路径,./your_program
是你想要运行的程序。这个命令会在 your_program
运行时将 mylib.so
加载到内存中,以便在程序调用相应函数时使用你提供的实现。
例题
qmemcpy(v21, &unk_400A7E, sizeof(v21));
v23 = __readfsqword(0x28u);
v3 = v20;
for ( i = 9LL; i; --i )
{
*(_DWORD *)v3 = 0;
v3 += 4;
}
v18 = 201527;
v19 = time(0LL);
do
{
for ( j = 0LL; j != 36; ++j )
{
v5 = 0LL;
v6 = time(0LL);
srand(233811181 - v19 + v6);
v7 = v20[j];
v20[j] = rand() ^ v7;
v8 = (&funny)[j];
while ( v5 < strlen(v8) )
{
v9 = v8[v5];
if ( (_BYTE)v9 == 105 )
{
v22[(int)v5] = 105;
}
else
{
if ( (_DWORD)v5 && v8[v5 - 1] != 32 )
v10 = __ctype_toupper_loc();
else
v10 = __ctype_tolower_loc();
v22[(int)v5] = (*v10)[v9];
}
++v5;
}
v22[(int)v5] = 0;
__printf_chk(1LL, byte_400A44, v22);
sleep(1u);
}
--v18;
}
while ( v18 );
v13 = v20;
__printf_chk(1LL, "KEY: ", v12);
do
{
v14 = (unsigned __int8)*v13++;
__printf_chk(1LL, "%02x ", v14);
}
while ( v13 != v21 );
v15 = 0LL;
putchar(10);
__printf_chk(1LL, "OK YOU WIN. HERE'S YOUR FLAG: ");
do
{
v16 = v21[v15] ^ v20[v15];
++v15;
putchar(v16);
}
while ( v15 != 36 );
putchar(10);
return 0;
}
整个代码流程主要包括一个循环,该循环负责不断输出 funny
数组中的句子,直到满足某个条件后输出 key
,并利用该 key
进行异或运算,从而得到 flag
的值。
考虑到循环次数相对较少,我们可以采取一些方法加速循环的执行。一种有效的方式是手动修改程序以禁止输出字符串(因为 printf
函数的调用会消耗相当多的时间)。同时,我们还可以利用 LD_PRELOAD
技术,重载 sleep()
函数,使其失效,从而显著节省时间。
直到0x4007BD
保存更新一下:
编写代码生成动态链接文件.
static int t = 0x31337;
void sleep(int sec) {
t += sec;
}
int time() {
return t;
}
然后使用命令gcc --shared time.c -o time.so
生成动态链接文件.
然后打开 linux 终端, 运行命令: LD_PRELOAD=./time.so ./hihb_bin100.elf