Skip to content

Commit 92300ee

Browse files
committed
Make header compatible with C
As such, it is also renamed dlhook.h Build compatibility has been expanded to C++14 Test compatibility has been expanded to Clang
1 parent 87aefd1 commit 92300ee

File tree

5 files changed

+46
-42
lines changed

5 files changed

+46
-42
lines changed

CMakeLists.txt

+2-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ cmake_minimum_required (VERSION 3.16)
33
project (dlhook)
44

55
add_library (dlhook SHARED)
6-
target_compile_features (dlhook PRIVATE cxx_std_17)
6+
target_compile_features (dlhook PRIVATE cxx_std_14)
77
target_include_directories (dlhook PUBLIC include)
8-
target_compile_options (dlhook PRIVATE -Wno-pointer-arith)
9-
target_sources (dlhook PRIVATE src/dlhook.cxx include/dlhook.hxx)
8+
target_sources (dlhook PRIVATE src/dlhook.cxx include/dlhook.h)
109

1110
if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
1211
include (CTest)

README.md

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
An extension to the dlfcn.h family, for attaching hooks to functions from DSOs.
44

5-
Requires C++17 to build, but also to interface.
6-
Interface will be switched over to C-compat eventually.
5+
Requires C++14 to build, but the interface is C compatible.
76

87
Supported platforms:
98
- Linux amd64 (manually tested), aarch64 (untested yet)
@@ -21,14 +20,14 @@ Synopsis:
2120
/// @param hook replacement entry for @a symbol.
2221
/// @return the original address found in the PLT
2322
/// @note if an error occurs, the program will be aborted
24-
void* dlhook_sym(void* handle, std::string_view symbol, void* hook);
23+
void* dlhook_sym(void* handle, const char* symbol, void* hook);
2524

2625
/// Hooks the PLT entries of @a symbol with @a hook in all currently loaded objects.
2726
///
2827
/// @param symbol which symbol to hook in the PLT of @a handle.
2928
/// @param hook replacement entry for @a symbol.
3029
/// @note if an error occurs, it will be safely ignored.
31-
void dlhook_sym_all(std::string_view symbol, void* hook);
30+
void dlhook_sym_all(const char* symbol, void* hook);
3231

3332
// Hook by address
3433

include/dlhook.hxx include/dlhook.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 AeroStun
2+
* Copyright 2023-2024 AeroStun
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,7 +16,9 @@
1616
#ifndef DLHOOK_HXX
1717
#define DLHOOK_HXX
1818

19-
#include <string_view>
19+
#ifdef __cplusplus
20+
extern "C" {
21+
#endif
2022

2123
// Hook by symbol
2224

@@ -28,14 +30,14 @@
2830
/// @param hook replacement entry for @a symbol.
2931
/// @return the original address found in the PLT
3032
/// @note if an error occurs, the program will be aborted
31-
void* dlhook_sym(void* handle, std::string_view symbol, void* hook);
33+
void* dlhook_sym(void* handle, const char* symbol, void* hook);
3234

3335
/// Hooks the PLT entries of @a symbol with @a hook in all currently loaded objects.
3436
///
3537
/// @param symbol which symbol to hook in the PLT of @a handle.
3638
/// @param hook replacement entry for @a symbol.
3739
/// @note if an error occurs, it will be safely ignored.
38-
void dlhook_sym_all(std::string_view symbol, void* hook);
40+
void dlhook_sym_all(const char* symbol, void* hook);
3941

4042
// Hook by address
4143

@@ -55,4 +57,8 @@ void dlhook_addr(void* handle, void* original, void* hook);
5557
/// @note if an error occurs, the program will be aborted.
5658
void dlhook_addr_all(void* original, void* hook);
5759

60+
#ifdef __cplusplus
61+
}
62+
#endif
63+
5864
#endif

src/dlhook.cxx

+22-19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 AeroStun
2+
* Copyright 2023-2024 AeroStun
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
1616
#include <cassert>
1717
#include <cstddef>
1818
#include <cstdint>
19+
#include <cstring>
1920
#include <map>
20-
#include <string>
2121

2222
#if defined(__linux__) && !defined(_GNU_SOURCE)
2323
# define _GNU_SOURCE
@@ -38,7 +38,7 @@
3838

3939
#include <unistd.h>
4040

41-
#include "dlhook.hxx"
41+
#include "dlhook.h"
4242

4343
#if !defined(R_X86_64_JUMP_SLOT) && defined(R_X86_64_JMP_SLOT)
4444
# define R_X86_64_JUMP_SLOT R_X86_64_JMP_SLOT
@@ -68,7 +68,7 @@ struct MaybeAddr {
6868
using DlLinkMap = struct link_map;
6969

7070
struct ObjectPltData {
71-
void* plt_addr_base{nullptr};
71+
std::uintptr_t plt_addr_base{0U};
7272

7373
const Elf64_Sym* dynsym{nullptr};
7474

@@ -138,7 +138,7 @@ static const DlLinkMap* get_lmap_for_handle(void* const handle) {
138138
}
139139

140140
template <class T>
141-
void force_write(T& dst, const T value) {
141+
static void force_write(T& dst, const T value) {
142142
#if defined(__linux__)
143143
// Set new target using FOLL_FORCE
144144
const int proc_self_mem = get_state().proc_self_mem;
@@ -170,7 +170,7 @@ void force_write(T& dst, const T value) {
170170
static ObjectPltData inspect_object(DlLinkMap const* obj_lmap) {
171171
ObjectPltData ret{};
172172

173-
ret.plt_addr_base = reinterpret_cast<void*>(obj_lmap->l_addr);
173+
ret.plt_addr_base = reinterpret_cast<std::uintptr_t>(obj_lmap->l_addr);
174174

175175
// Locate symbol table
176176
const Elf64_Dyn* dyn_symtab = find_dyn_by_tag(obj_lmap->l_ld, DT_SYMTAB);
@@ -242,15 +242,15 @@ static ObjectPltData inspect_object(DlLinkMap const* obj_lmap) {
242242

243243
template <class Callback>
244244
static void foreach_plt_or_got(const ObjectPltData& obj, Callback&& callback) {
245-
auto filter_relas = [&](const auto& rela, const Elf64_Xword reloc_type) -> bool {
245+
auto const filter_relas = [&](const auto& rela, const Elf64_Xword reloc_type) -> bool {
246246
if (ELF64_R_TYPE(rela.r_info) == reloc_type) {
247247
// Sanity check of the symbol name's index
248248
const std::size_t idx = obj.dynsym[ELF64_R_SYM(rela.r_info)].st_name;
249249
if (idx + 1 > obj.dynstr_size) {
250250
return false;
251251
}
252252

253-
return callback(obj.dynstr + idx, *static_cast<void**>(obj.plt_addr_base + rela.r_offset));
253+
return callback(obj.dynstr + idx, *reinterpret_cast<void**>(obj.plt_addr_base + rela.r_offset));
254254
}
255255

256256
return true;
@@ -275,7 +275,7 @@ static ObjectPltData get_object(const DlLinkMap* lmap) {
275275
ObjectPltData object{};
276276
if (it == obj_cache.end()) {
277277
object = inspect_object(lmap);
278-
if (object.plt_addr_base == nullptr) {
278+
if (object.plt_addr_base == 0U) {
279279
return {};
280280
}
281281
obj_cache.emplace(lmap, object);
@@ -286,20 +286,21 @@ static ObjectPltData get_object(const DlLinkMap* lmap) {
286286
return object;
287287
}
288288

289-
static MaybeAddr dlhook_sym(const DlLinkMap* lmap, const std::string_view symbol, void* const hook) {
289+
static MaybeAddr dlhook_sym(const DlLinkMap* lmap, const char* const symbol, void* const hook) {
290290
if (lmap == nullptr) {
291291
return {};
292292
}
293293

294+
auto const symbol_length = std::strlen(symbol);
295+
294296
MaybeAddr result{};
295-
const auto callback = [symbol, hook, &result](std::string_view name, void*& ptr) -> bool {
297+
const auto callback = [symbol, symbol_length, hook, &result](const char* const name, void*& ptr) -> bool {
296298
// if (!name.starts_with(symbol))
297-
if (name.substr(0, symbol.size()) != symbol) {
299+
if (std::strncmp(name, symbol, symbol_length) != 0) {
298300
// Keep going
299301
return true;
300302
}
301-
name.remove_prefix(symbol.size());
302-
if (!name.empty() && name.front() != '@') {
303+
if (name[symbol_length] != '\0' && name[symbol_length] != '@') {
303304
// Keep going
304305
return true;
305306
}
@@ -318,13 +319,13 @@ static MaybeAddr dlhook_sym(const DlLinkMap* lmap, const std::string_view symbol
318319
return result;
319320
}
320321

321-
void* dlhook_sym(void* const handle, const std::string_view symbol, void* const hook) {
322+
extern "C" void* dlhook_sym(void* const handle, const char* const symbol, void* const hook) {
322323
const auto result = dlhook_sym(get_lmap_for_handle(handle), symbol, hook);
323324
assert(result.valid);
324325
return result.addr;
325326
}
326327

327-
void dlhook_sym_all(const std::string_view symbol, void* hook) {
328+
extern "C" void dlhook_sym_all(const char* symbol, void* hook) {
328329
for (auto it = _r_debug.r_map; it != nullptr; it = it->l_next) {
329330
const auto result = dlhook_sym(it, symbol, hook);
330331
if (!result.valid) {
@@ -338,7 +339,7 @@ static void dlhook_addr(const DlLinkMap* lmap, void* original, void* hook) {
338339
return;
339340
}
340341

341-
const auto callback = [original, hook](std::string_view, void*& ptr) -> bool {
342+
const auto callback = [original, hook](const char*, void*& ptr) -> bool {
342343
if (ptr != original) {
343344
// Keep going
344345
return true;
@@ -352,9 +353,11 @@ static void dlhook_addr(const DlLinkMap* lmap, void* original, void* hook) {
352353
foreach_plt_or_got(get_object(lmap), callback);
353354
}
354355

355-
void dlhook_addr(void* handle, void* original, void* hook) { dlhook_addr(get_lmap_for_handle(handle), original, hook); }
356+
extern "C" void dlhook_addr(void* handle, void* original, void* hook) {
357+
dlhook_addr(get_lmap_for_handle(handle), original, hook);
358+
}
356359

357-
void dlhook_addr_all(void* original, void* hook) {
360+
extern "C" void dlhook_addr_all(void* original, void* hook) {
358361
for (auto it = _r_debug.r_map; it != nullptr; it = it->l_next) {
359362
dlhook_addr(it, original, hook);
360363
}

test/test.cxx

+9-12
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
#include <cassert>
2-
#include "dlhook.hxx"
2+
#include "dlhook.h"
33
#include "test.hxx"
44

5-
extern "C" int hook() {
6-
return 0xF00L;
7-
}
5+
extern "C" int hook() { return 0xF00L; }
86

97
int main() {
10-
const auto direct_addr = reinterpret_cast<void*>(&direct);
118
const auto hook_addr = reinterpret_cast<void*>(&hook);
129

1310
assert(direct() == 0xBEEF);
1411
assert(indirect() == 0xBEEF);
1512

1613
auto* real = dlhook_sym(nullptr, "direct", hook_addr);
17-
assert(reinterpret_cast<int(*)()>(real)() == 0xBEEF);
14+
assert(reinterpret_cast<int (*)()>(real)() == 0xBEEF);
1815
assert(direct() == 0xF00L);
1916
assert(indirect() == 0xBEEF);
2017

@@ -23,19 +20,19 @@ int main() {
2320
assert(direct() == 0xBEEF);
2421
assert(indirect() == 0xBEEF);
2522

26-
//dlhook_sym_all("direct", hook_addr);
27-
//assert(direct() == 0xF00L);
28-
//assert(indirect() == 0xF00L);
23+
// dlhook_sym_all("direct", hook_addr);
24+
// assert(direct() == 0xF00L);
25+
// assert(indirect() == 0xF00L);
2926

30-
dlhook_addr(nullptr, direct_addr, hook_addr);
27+
dlhook_addr(nullptr, real, hook_addr);
3128
assert(direct() == 0xF00L);
3229
assert(indirect() == 0xBEEF);
3330

34-
dlhook_addr(nullptr, hook_addr, direct_addr);
31+
dlhook_addr(nullptr, hook_addr, real);
3532
assert(direct() == 0xBEEF);
3633
assert(indirect() == 0xBEEF);
3734

38-
dlhook_addr_all(direct_addr, hook_addr);
35+
dlhook_addr_all(real, hook_addr);
3936
assert(direct() == 0xF00L);
4037
assert(indirect() == 0xF00L);
4138
}

0 commit comments

Comments
 (0)