diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 0e25bec..f7c92e5 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -13,20 +13,26 @@ jobs: steps: - uses: actions/checkout@v2 - - name: configure cmake for library + - name: Configure CMake run: cmake -G "MinGW Makefiles" -B build - - name: build library + - name: Generate revision information + shell: bash + run: | + curl https://raw.githubusercontent.com/Autorevision/autorevision/master/autorevision.sh -o autorevision + ./autorevision -t h > autorevision.h + + - name: Build libhack run: make working-directory: build - - name: configure cmake for examples + - name: Configure CMake (examples) run: | cp ../../build/*.dll libhack.dll cp ../../build/*.a libhack.a cmake -G "MinGW Makefiles" -B build working-directory: src/examples - - name: build examples + - name: Build examples run: make working-directory: src/examples/build diff --git a/.gitignore b/.gitignore index b092680..95026c1 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,4 @@ CTestTestfile.cmake _deps # Autorevision generated file -#autorevision.h \ No newline at end of file +autorevision* \ No newline at end of file diff --git a/CMakelists.txt b/CMakelists.txt index 9367db8..f369576 100644 --- a/CMakelists.txt +++ b/CMakelists.txt @@ -11,6 +11,8 @@ add_library(hack SHARED src/process.h src/consts.h src/init.h + src/logger.c + src/logger.h ) # configure target properties @@ -29,6 +31,10 @@ if(MINGW) #set(CMAKE_C_FLAGS "-m32") elseif(MSVC) add_definitions(-DVISUAL_STUDIO) + if (NOT MSVC_VERSION LESS 1900) + message(AUTHOR_WARNING "Disabling spectre mitigation") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Qspectre-") + endif() endif() diff --git a/src/autorevision.h b/src/autorevision.h deleted file mode 100644 index 55d5f2a..0000000 --- a/src/autorevision.h +++ /dev/null @@ -1,25 +0,0 @@ -/* Generated by autorevision - do not hand-hack! */ -#ifndef AUTOREVISION_H -#define AUTOREVISION_H - -#define VCS_TYPE "git" -#define VCS_BASENAME "libhack" -#define VCS_UUID "9156326fc1af8274445475661bc0c19952a515f4" -#define VCS_NUM 61 -#define VCS_DATE "2020-10-24T22:33:44Z" -#define VCS_BRANCH "dev" -#define VCS_TAG "v0.2.0" -#define VCS_TAG_OPENPGP "" -#define VCS_TICK 0 -#define VCS_EXTRA "" - -#define VCS_ACTION_STAMP "2020-10-24T22:33:44Z!lucas.engen.cc@gmail.com" -#define VCS_FULL_HASH "a9ae99f4b119c1e7fcb60d01fef61dfe69bb6dd5" -#define VCS_COMMIT_OPENPGP "363DA20EA449B53085CD4A466512BE6BAE730817" -#define VCS_SHORT_HASH "a9ae99f" - -#define VCS_WC_MODIFIED 1 - -#endif - -/* end */ diff --git a/src/examples/CMakelists.txt b/src/examples/CMakelists.txt index 0aa4be9..be44728 100644 --- a/src/examples/CMakelists.txt +++ b/src/examples/CMakelists.txt @@ -22,3 +22,12 @@ target_link_libraries(write_addr ${LIBHACK}) target_link_libraries(dll_inject ${LIBHACK}) target_link_libraries(version_info ${LIBHACK}) target_link_libraries(submodule_addr ${LIBHACK}) + +# Set language standard +set_property(TARGET pid PROPERTY C_STANDARD 11) +set_property(TARGET read_addr PROPERTY C_STANDARD 11) +set_property(TARGET write_addr PROPERTY C_STANDARD 11) +set_property(TARGET dll_inject PROPERTY C_STANDARD 11) +set_property(TARGET version_info PROPERTY C_STANDARD 11) +set_property(TARGET submodule_addr PROPERTY C_STANDARD 11) + diff --git a/src/examples/write_addr.c b/src/examples/write_addr.c index 12e8bf6..b6d2e91 100644 --- a/src/examples/write_addr.c +++ b/src/examples/write_addr.c @@ -56,7 +56,7 @@ int main() */ libhack_write_int_to_addr(hack, baseAddr + 0x4c, value); - printf("Value readed from address %#x: %d\n", baseAddr + 0x4c, value); + printf("Value written to address %#x: %d\n", baseAddr + 0x4c, value); /* Cleanup resources used by library diff --git a/src/init.c b/src/init.c index 2393456..9a7ae99 100644 --- a/src/init.c +++ b/src/init.c @@ -14,7 +14,8 @@ #include #include #include "init.h" -#include "autorevision.h" +#include "logger.h" +#include "../autorevision.h" /** * @brief Contains version number @@ -22,11 +23,17 @@ */ static char version[VERSION_NUMBER_LEN]; -/** - * @brief Gets library version - * - * @return const char* The lib version in format MAJOR.MINOR.PATCH build BUILD - */ +LIBHACK_API const char *libhack_get_platform() +{ +#if defined(__x86__) + return "32-bit"; +#elif defined(__x64__) + return "64-bit"; +#else + return "unknown"; +#endif +} + LIBHACK_API const char *libhack_getversion() { RtlSecureZeroMemory(version, sizeof(version)); @@ -52,8 +59,8 @@ static BOOL libhack_check_version() const char *uuid = libhack_getuuid(); if(strncmp(uuid, VCS_UUID, strlen(VCS_UUID)) != 0) { - libhack_debug("version mismatch: %s build %d != %s\n", VCS_TAG, VCS_NUM, libhack_getversion()); - libhack_debug("this version has been built on %s\n", VCS_DATE); + libhack_debug("Version mismatch: %s build %d != %s\n", VCS_TAG, VCS_NUM, libhack_getversion()); + libhack_debug("This version has been built on %s\n", VCS_DATE); return FALSE; } @@ -80,18 +87,15 @@ struct libhack_handle *libhack_init(const char *process_name) } // Initialize memory - RtlSecureZeroMemory(lh->process_name, sizeof(lh->process_name)); + RtlSecureZeroMemory(lh, sizeof(struct libhack_handle)); /* Copy process name to internal variable */ strncpy(lh->process_name, process_name, sizeof(lh->process_name) / sizeof(lh->process_name[0])); - - lh->pid = 0; - lh->base_addr = 0; - lh->hProcess = NULL; - lh->hModule = NULL; - lh->bProcessIsOpen = FALSE; - libhack_debug("initialized libhack version %s\n", libhack_getversion()); + // Transform process name to lowercase + strlwr(lh->process_name); + + libhack_debug("Initialized libhack version %s (%s)\n", libhack_getversion(), libhack_get_platform()); return lh; } diff --git a/src/init.h b/src/init.h index 6fab612..e9bad03 100644 --- a/src/init.h +++ b/src/init.h @@ -13,6 +13,7 @@ #define LIBHACK_H #include "consts.h" +#include "platform.h" #include #include @@ -29,39 +30,25 @@ extern "C" { #endif /** - * @brief Obtém o tamanho do vetor + * @brief Gets the number of elements in a vector * */ #define arraySize(x) (sizeof(x)/sizeof(x[0])) -/** - * @brief Shows a message if the program is being debugged - * - */ -#if defined(DEBUG) || !defined(NDEBUG) -#define libhack_debug(...) fprintf(stdout, "[libhack] " __VA_ARGS__) -#else -#ifdef _MSC_VER -#define libhack_debug(...) -#else -#define libhack_debug(...) asm("nop\n\t") -#endif -#endif - #define libhack_assert_or_exit(condition, exit_code) \ - if(!condition) { \ - fprintf(stdout, "libhack assert failure on %s line %d\n", __FILE__, __LINE__); \ + if(!(condition)) { \ + fprintf(stdout, "[LIBHACK] warn: assert failure on %s line %d\n", __FILE__, __LINE__); \ exit(exit_code); \ } #define libhack_assert_or_warn(condition) \ - if(!condition) { \ - fprintf(stdout, "warn: assert failure on %s line %d\n", __FILE__, __LINE__); \ + if(!(condition)) { \ + fprintf(stdout, "[LIBHACK] warn: assert failure on %s line %d\n", __FILE__, __LINE__); \ } #define libhack_assert_or_return(condition, retval) \ - if(!condition) { \ - fprintf(stdout, "warn: assert failure on %s line %d\n", __FILE__, __LINE__); \ + if(!(condition)) { \ + fprintf(stdout, "[LIBHACK] warn: assert failure on %s line %d\n", __FILE__, __LINE__); \ return retval; \ } @@ -81,13 +68,20 @@ struct libhack_handle * @brief Process identifier * */ - DWORD64 pid; - + DWORD pid; +#if defined(__x64__) /** * @brief Process base address * */ DWORD64 base_addr; +#else + /** + * @brief Process base address + * + */ + DWORD base_addr; +#endif /** * @brief Process handle @@ -106,8 +100,21 @@ struct libhack_handle * */ BOOL bProcessIsOpen; + + /** + * @brief Flag to check if process is a x64 process + * + */ + BOOL b64BitProcess; }; +/** + * @brief Gets the target platform of library + * + * @return LIBHACK_API const* platform string + */ +LIBHACK_API const char *libhack_get_platform(); + /** * @brief Gets the program version and return a string * diff --git a/src/logger.c b/src/logger.c new file mode 100644 index 0000000..23e73ab --- /dev/null +++ b/src/logger.c @@ -0,0 +1,50 @@ + +#include +#include +#include "logger.h" + +#if defined(DEBUG) || !defined(NDEBUG) +void libhack_debug(const char *msg, ...) +{ + va_list list; + + va_start(list, msg); + fprintf(stdout, "[LIBHACK DEBUG] "); + vfprintf(stdout, msg, list); + fprintf(stdout, "\n"); + va_end(list); +} + +void libhack_warn(const char *msg, ...) +{ + va_list list; + + va_start(list, msg); + fprintf(stdout, "[LIBHACK WARNING] "); + vfprintf(stdout, msg, list); + fprintf(stdout, "\n"); + va_end(list); +} + +void libhack_notice(const char *msg, ...) +{ + va_list list; + + va_start(list, msg); + fprintf(stdout, "[LIBHACK INFO] "); + vfprintf(stdout, msg, list); + fprintf(stdout, "\n"); + va_end(list); +} + +void libhack_err(const char *msg, ...) +{ + va_list list; + + va_start(list, msg); + fprintf(stdout, "[LIBHACK ERROR] "); + vfprintf(stdout, msg, list); + fprintf(stdout, "\n"); + va_end(list); +} +#endif diff --git a/src/logger.h b/src/logger.h new file mode 100644 index 0000000..afa9c33 --- /dev/null +++ b/src/logger.h @@ -0,0 +1,21 @@ +#ifndef LOGGER_H +#define LOGGER_H + +/** + * @brief Shows a message if the program is being debugged + * + */ + +#if defined(DEBUG) || !defined(NDEBUG) +extern void libhack_debug(const char *msg, ...); +extern void libhack_warn(const char *msg, ...); +extern void libhack_notice(const char *msg, ...); +extern void libhack_err(const char *msg, ...); +#else +#define libhack_debug(...) +#define libhack_warn(...) +#define libhack_notice(...) +#define libhack_err(...) +#endif + +#endif diff --git a/src/platform.h b/src/platform.h new file mode 100644 index 0000000..a521ad7 --- /dev/null +++ b/src/platform.h @@ -0,0 +1,13 @@ +#ifndef PLATFORM_H +#define PLATFORM_H + + +#if defined(__MINGW64__) || defined(_WIN64) +#define __x64__ +#elif __MINGW32__ || defined(_WIN32) +#define __x86__ +#else +#error "Unknown platform detected" +#endif + +#endif // PLATFORM_H diff --git a/src/process.c b/src/process.c index 1ffdcc0..6555a0c 100644 --- a/src/process.c +++ b/src/process.c @@ -15,10 +15,13 @@ #include #include #include +#include #ifndef bool #include #endif #include "process.h" +#include "platform.h" +#include "logger.h" /** * @brief Checking types @@ -29,6 +32,12 @@ enum CHECK_TYPES { READ_CHECK }; +/** + * @brief Pointer to IsWow64Process function + * + */ +typedef bool (*pIsWow64Process)(HANDLE hProcess, bool *isWow64); + /** * @brief Checks if the specified handle can be used to specified 'type' access * @@ -39,19 +48,15 @@ enum CHECK_TYPES { */ static bool libhack_perform_check(struct libhack_handle *handle, enum CHECK_TYPES type) { - switch(type) - { - case WRITE_CHECK: - case READ_CHECK: - - // Checks if the process can be opened for read or write - if((!handle) || !(handle->bProcessIsOpen)) - return false; + bool bCheck = true; - break; + if(type & WRITE_CHECK || type & READ_CHECK) { + // Checks if the process can be opened for read or write + if((!handle) || !(handle->bProcessIsOpen)) + return false; } - return true; + return bCheck; } /** @@ -61,24 +66,26 @@ static bool libhack_perform_check(struct libhack_handle *handle, enum CHECK_TYPE * @param b64bit TRUE if the process is 64 bit * @return long Number of modules loaded */ -static long libhack_get_modules_count(struct libhack_handle *handle, BOOL b64bit) +static long libhack_get_modules_count(struct libhack_handle *handle, short filter) { HMODULE module; DWORD needed; - BOOL status; - DWORD filter = b64bit ? LIST_MODULES_64BIT : LIST_MODULES_32BIT; + bool status; status = K32EnumProcessModulesEx(handle->hProcess, &module, 0, &needed, filter); - libhack_assert_or_return(status, -1); + libhack_assert_or_return(status != FALSE, -1); - return (long)needed; + return (long)needed / sizeof(HMODULE); } -BOOL libhack_open_process(struct libhack_handle *handle) +bool libhack_open_process(struct libhack_handle *handle) { + bool bIs64 = false; + DWORD err; + if(!handle) - return FALSE; + return false; /* Check if the process is already open */ if(!handle->bProcessIsOpen) @@ -89,23 +96,29 @@ BOOL libhack_open_process(struct libhack_handle *handle) handle->hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if(!handle->hProcess) { - libhack_debug("Failed to open process with pid %lu: %lu\n", pid, GetLastError()); - return FALSE; + libhack_debug("Failed to open process with pid %lu: %lu", pid, GetLastError()); + return false; } - /* Update flag */ + // Setup flags handle->bProcessIsOpen = TRUE; + + bIs64 = libhack_is64bit_process(handle, &err); + if(err == ERROR_SUCCESS) { + libhack_debug("%s is 64-bit: %s", handle->process_name, bIs64 ? "yes" : "no"); + handle->b64BitProcess = bIs64; + } - return TRUE; + return true; } - return FALSE; + return false; } /* Handle already opened */ SetLastError(ERROR_ALREADY_INITIALIZED); - return TRUE; + return true; } DWORD libhack_get_process_id(struct libhack_handle *handle) @@ -128,7 +141,7 @@ DWORD libhack_get_process_id(struct libhack_handle *handle) entry = (PROCESSENTRY32*)malloc(sizeof(PROCESSENTRY32)); if(!entry) { - libhack_debug("Failed to allocate memory\n"); + libhack_debug("Failed to allocate memory"); return 0; } @@ -136,12 +149,12 @@ DWORD libhack_get_process_id(struct libhack_handle *handle) hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(!hSnapshot) { - libhack_debug("Failed to create snapshot\n"); + libhack_debug("Failed to create snapshot"); return 0; } if(!Process32First(hSnapshot, entry)) { - libhack_debug("Failed to initialize process list: %lu\n", GetLastError()); + libhack_debug("Failed to initialize process list: %lu", GetLastError()); return 0; } @@ -172,13 +185,13 @@ int libhack_read_int_from_addr64(struct libhack_handle *handle, DWORD64 addr) /* Validate handle */ if(!libhack_perform_check(handle, READ_CHECK)) { - libhack_debug("check failed! Either process is not opened or handle is invalid\n"); + libhack_debug("Check failed! Either process is not opened or handle is invalid"); return -1; } /* Read memory at the specified address */ if(!ReadProcessMemory(handle->hProcess, (const void*)addr, (void*)&value, sizeof(int), &readed)) { - libhack_debug("Failed to read memory: %lu\n", GetLastError()); + libhack_debug("Failed to read memory: %lu", GetLastError()); return -1; } @@ -191,13 +204,13 @@ int libhack_write_int_to_addr64(struct libhack_handle *handle, DWORD64 addr, int /* Validate parameters */ if(!libhack_perform_check(handle, WRITE_CHECK)) { - libhack_debug("check failed! Either process is not opened or handle is invalid\n"); + libhack_debug("Check failed! Either process is not opened or handle is invalid"); return -1; } /* Write memory at the specified address */ if(!WriteProcessMemory(handle->hProcess, (void*)addr, (const void*)&value, sizeof(int), &written)) { - libhack_debug("Failed to write memory: %lu\n", GetLastError()); + libhack_debug("Failed to write memory: %lu", GetLastError()); return -1; } @@ -206,38 +219,77 @@ int libhack_write_int_to_addr64(struct libhack_handle *handle, DWORD64 addr, int DWORD64 libhack_get_base_addr64(struct libhack_handle *handle) { - HMODULE module; - DWORD needed; - char procName[BUFLEN]; + HMODULE *modules = NULL; + DWORD needed = 0; + char moduleName[BUFLEN]; + long count = 0; + unsigned short filter = LIST_MODULES_64BIT; /* Validate parameters */ if(!libhack_perform_check(handle, READ_CHECK)) { - libhack_debug("check failed! Either process is not opened or handle is invalid\n"); - return -1; + libhack_debug("Check failed! Either process is not opened or handle is invalid"); + return 0; } - /* Initialize memory */ - RtlSecureZeroMemory(procName, sizeof(procName)); +#ifdef __x86__ + libhack_warn("We're calling the x64 version of libhack_get_base_addr instead of x86 version"); +#elif defined(__x64__) + if(!handle->b64BitProcess) { + libhack_warn("You're trying to get the base address of a 32-bit process using a 64-bit function"); + } +#endif + /* Initialize memory */ + RtlSecureZeroMemory(moduleName, sizeof(moduleName)); + /* Check if we have a base address already */ - if(handle->base_addr) - return handle->base_addr; + if(handle->base_addr) { + return handle->base_addr; + } + + count = libhack_get_modules_count(handle, filter); + + // Check if previous calling failed + libhack_assert_or_return(count > 0, 0); + + modules = (HMODULE*)malloc(sizeof(HMODULE) * count); + if(modules == NULL) + { + libhack_err("We're out of memory"); + return 0; + } /* Enumerate process modules */ - if(K32EnumProcessModulesEx(handle->hProcess, &module, sizeof(HMODULE), &needed, LIST_MODULES_ALL)) + if(K32EnumProcessModulesEx(handle->hProcess, modules, count, &needed, filter)) { - K32GetModuleBaseNameA(handle->hProcess, module, procName, BUFLEN); + for(unsigned i = 0; i < (needed / sizeof(HMODULE)); ++i) { + // Get module names + K32GetModuleBaseNameA(handle->hProcess, modules[i], moduleName, arraySize(moduleName)); - libhack_debug("Name: %s (%s)\n", procName, handle->process_name); + // Convert module name to lowercase + strlwr(moduleName); - if(strnicmp(procName, handle->process_name, strlen(handle->process_name)) == 0) - { - handle->hModule = module; - return (DWORD64)module; - } - } - - libhack_debug("we failed to get process base address: %lu\n", GetLastError()); + // Compare module name + if(strnicmp(moduleName, handle->process_name, strlen(handle->process_name)) == 0) + { + DWORD64 modAddr = modules[i]; + + // Free memory + free(modules); + + handle->hModule = modAddr; + return (DWORD64)modAddr; + } + } + } else { + libhack_err("Failed to enumerate process modules: %lu", GetLastError()); + libhack_debug("Needed/Count: %lu/%lu", needed, count); + } + + // Free memory + free(modules); + + libhack_debug("We failed to get process base address: %lu", GetLastError()); return 0; } @@ -249,13 +301,13 @@ LIBHACK_API int libhack_read_int_from_addr(struct libhack_handle *handle, DWORD /* Validate handle */ if(!libhack_perform_check(handle, READ_CHECK)) { - libhack_debug("check failed! Either process is not opened or handle is invalid\n"); + libhack_debug("Check failed! Either process is not opened or handle is invalid"); return -1; } /* Read memory at the specified address */ - if(!ReadProcessMemory(handle->hProcess, (const void*)addr, (void*)&value, sizeof(DWORD), &readed)) { - libhack_debug("Failed to read memory: %lu\n", GetLastError()); + if(!ReadProcessMemory(handle->hProcess, (const void*)addr, (void*)&value, sizeof(int), &readed)) { + libhack_debug("Failed to read memory: %lu", GetLastError()); return -1; } @@ -268,7 +320,7 @@ LIBHACK_API int libhack_write_int_to_addr(struct libhack_handle *handle, DWORD a /* Validate parameters */ if(!libhack_perform_check(handle, READ_CHECK)) { - libhack_debug("check failed! Either process is not opened or handle is invalid\n"); + libhack_debug("Check failed! Either process is not opened or handle is invalid"); return -1; } @@ -283,14 +335,19 @@ LIBHACK_API int libhack_write_int_to_addr(struct libhack_handle *handle, DWORD a LIBHACK_API DWORD libhack_get_base_addr(struct libhack_handle *handle) { - HMODULE module; + HMODULE *modules = NULL; DWORD needed; char procName[BUFLEN]; + unsigned short filter = LIST_MODULES_32BIT; /* Validate parameters */ if(!libhack_perform_check(handle, READ_CHECK)) { - libhack_debug("check failed! Either process is not opened or handle is invalid\n"); - return -1; + libhack_debug("Check failed! Either process is not opened or handle is invalid"); + return 0; + } + + if(handle->b64BitProcess) { + libhack_warn("We're using the 32-bit function to get a 64-bit address"); } /* Initialize memory */ @@ -300,35 +357,65 @@ LIBHACK_API DWORD libhack_get_base_addr(struct libhack_handle *handle) if(handle->base_addr) return handle->base_addr; + long count = libhack_get_modules_count(handle, filter); + libhack_assert_or_return(count > 0, 0); + + modules = (HMODULE*)malloc(sizeof(HMODULE) * count); + if(modules == NULL) + { + libhack_err("We're out of memory"); + return 0; + } + /* Enumerate process modules */ - if(K32EnumProcessModulesEx(handle->hProcess, &module, sizeof(HMODULE), &needed, LIST_MODULES_ALL)) + if(K32EnumProcessModulesEx(handle->hProcess, modules, count, &needed, filter)) { - K32GetModuleBaseNameA(handle->hProcess, module, procName, BUFLEN); + for(unsigned i = 0; i < count; i++) { + + // Get module name + K32GetModuleBaseNameA(handle->hProcess, modules[i], procName, BUFLEN); + + // Transform name to lowercase + strlwr(procName); + + // Check if module is the main module + if(strnicmp(procName, handle->process_name, strlen(handle->process_name)) == 0) + { + DWORD modAddr = (DWORD)modules[i]; + handle->hModule = modules[i]; + + // Free memory + free(modules); + + return modAddr; + } + } + } else { + libhack_err("Failed to enumarate process modules"); + } + + // Cleanup resources + free(modules); + + libhack_debug("Failed to get process base address: %u", GetLastError()); - if(strnicmp(procName, handle->process_name, strlen(handle->process_name)) == 0) - { - handle->hModule = module; - return (DWORD)module; - } - } - return 0; } -LIBHACK_API BOOL libhack_process_is_running(struct libhack_handle *handle) +LIBHACK_API bool libhack_process_is_running(struct libhack_handle *handle) { DWORD state; // Validate parameters if(!libhack_perform_check(handle, READ_CHECK)) { - libhack_debug("check failed! Either process is not opened or handle is invalid\n"); + libhack_debug("Check failed! Either process is not opened or handle is invalid"); return FALSE; } // Try to get exit code of the process if any if(!GetExitCodeProcess(handle->hProcess, &state)) { - libhack_debug("Failed to get process exit code\n"); + libhack_debug("Failed to get process exit code"); return FALSE; } @@ -341,11 +428,13 @@ LIBHACK_API int libhack_write_string_to_addr(struct libhack_handle *handle, DWOR /* Validate parameters */ if(!libhack_perform_check(handle, WRITE_CHECK)) { - libhack_debug("check failed! Either process is not opened or handle is invalid\n"); + libhack_debug("check failed! Either process is not opened or handle is invalid"); return -1; } - libhack_debug("Address: %#llx\n", addr); + if(handle->b64BitProcess) { + libhack_warn("You're trying to write a string into a x64 process by using a 32 bit address"); + } /* Write memory at the specified address */ if(!WriteProcessMemory(handle->hProcess, (void*)addr, string, string_len, &written)) { @@ -362,10 +451,16 @@ int libhack_write_string_to_addr64(struct libhack_handle *handle, DWORD64 addr, /* Validate parameters */ if(!libhack_perform_check(handle, WRITE_CHECK)) { - libhack_debug("check failed! Either process is not opened or handle is invalid\n"); + libhack_debug("Check failed! Either process is not opened or handle is invalid"); return -1; } +#ifdef __x86__ + if(handle->b64BitProcess) { + libhack_warn("Please, use the 32-bit version of this function: libhack_write_string_to_addr()"); + } +#endif + /* Write memory at the specified address */ if(!WriteProcessMemory(handle->hProcess, (void*)addr, string, string_len, &written)) { libhack_debug("Failed to write memory: %lu\n", GetLastError()); @@ -375,7 +470,7 @@ int libhack_write_string_to_addr64(struct libhack_handle *handle, DWORD64 addr, return written ? (int)written : 0; } -LIBHACK_API BOOL libhack_inject_dll(struct libhack_handle *handle, const char *dll_path) +LIBHACK_API bool libhack_inject_dll(struct libhack_handle *handle, const char *dll_path) { void *pDllPath = NULL; DWORD threadId; @@ -388,13 +483,13 @@ LIBHACK_API BOOL libhack_inject_dll(struct libhack_handle *handle, const char *d libhack_assert_or_return(dll_path, FALSE); if(!handle->bProcessIsOpen) { - libhack_debug("you need to call libhack_open_process() before trying to inject dll on it\n"); - return FALSE; + libhack_debug("You need to call libhack_open_process() before trying to inject dll on it"); + return false; } if(!PathFileExistsA(dll_path)) { - libhack_debug("%s could not be found. Don't forget to specify a full path to dll\n", dll_path); - return FALSE; + libhack_debug("%s could not be found. Don't forget to specify a full path to dll", dll_path); + return false; } hKernel32 = LoadLibraryA("kernel32.dll"); @@ -405,16 +500,22 @@ LIBHACK_API BOOL libhack_inject_dll(struct libhack_handle *handle, const char *d // Allocate memory to store full path of dll to be loaded into target process memory pDllPath = VirtualAllocEx(handle->hProcess, NULL, dll_path_len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if(!pDllPath) { - libhack_debug("virtual alloc failed: %lu\n", GetLastError()); - return FALSE; + libhack_debug("Virtual alloc failed: %lu", GetLastError()); + return false; } if(!WriteProcessMemory(handle->hProcess, pDllPath, dll_path, dll_path_len, NULL)) { - libhack_debug("failed to write process memory: %lu\n", GetLastError()); + libhack_debug("Failed to write process memory: %lu", GetLastError()); VirtualFreeEx(handle->hProcess, pDllPath, dll_path_len, MEM_RELEASE); - return FALSE; + return false; } +#ifdef __x86__ + if(handle->b64BitProcess) { + libhack_warn("You're trying to inject a dll into a x64 process from a 32-bit dll"); + } +#endif + // Creates the remote thread on target process that will load library hRemoteThread = CreateRemoteThread(handle->hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryA"), @@ -422,45 +523,53 @@ LIBHACK_API BOOL libhack_inject_dll(struct libhack_handle *handle, const char *d // Checks if dll injection was completed if(!hRemoteThread) { - libhack_debug("failed to inject dll: %lu\n", GetLastError()); - return FALSE; + libhack_debug("Failed to inject dll: %lu", GetLastError()); + return false; } // Once library is loaded we can release all resources if(!VirtualFreeEx(handle->hProcess, pDllPath, dll_path_len, MEM_RELEASE)) { - libhack_debug("warn: dll injection was successfull but we failed to free virtual memory: %lu\n", GetLastError()); + libhack_debug("DLL injection was successfull but we failed to free virtual memory: %lu", GetLastError()); } libhack_assert_or_warn(CloseHandle(hRemoteThread)); // TRUE because dll was injected on target process - return TRUE; + return true; } LIBHACK_API DWORD libhack_getsubmodule_addr(struct libhack_handle *handle, const char *module_name) { char basename[MAX_PATH]; DWORD addr = 0; + unsigned short filter = LIST_MODULES_32BIT; // Parameter validation libhack_assert_or_return(handle, 0); libhack_assert_or_return(handle->bProcessIsOpen, 0); // Check how many modules we have - long count = libhack_get_modules_count(handle, FALSE); + long count = libhack_get_modules_count(handle, filter); libhack_assert_or_return(count > 0, 0); + if(handle->b64BitProcess) { + libhack_warn("You're are getting the submodule address loaded by a x64 process with a 32 bit function"); + } + HMODULE *modules = (HMODULE*)malloc(sizeof(HMODULE) * count); DWORD needed = 0; libhack_assert_or_return(modules, 0); - if(K32EnumProcessModulesEx(handle->hProcess, modules, count, &needed, LIST_MODULES_32BIT)) + if(K32EnumProcessModulesEx(handle->hProcess, modules, count, &needed, filter)) { - for(long i = 0; i < count; i++) { - if(K32GetModuleBaseNameA(handle->hProcess, modules[i], basename, sizeof(basename))) { - char *name = strlwr(basename); + for(long i = 0; i < count; i++) + { + if(K32GetModuleBaseNameA(handle->hProcess, modules[i], basename, arraySize(basename))) + { + // Convert basename to lowercase + strlwr(basename); - if(strncmp(name, module_name, strlen(module_name)) == 0) { + if(strnicmp(basename, module_name, strlen(module_name)) == 0) { addr = (DWORD)modules[i]; break; } @@ -477,26 +586,36 @@ LIBHACK_API DWORD64 libhack_getsubmodule_addr64(struct libhack_handle *handle, c { char basename[MAX_PATH]; DWORD64 addr = 0; + unsigned short filter = LIST_MODULES_64BIT; // Parameter validation libhack_assert_or_return(handle, 0); libhack_assert_or_return(handle->bProcessIsOpen, 0); +#ifdef __x86__ + if(handle->b64BitProcess) { + libhack_warn("You're calling a x64 function inside a 32-bit DLL"); + libhack_warn("Please, use the x86 version: libhack_getsubmodule_addr()"); + } +#endif + // Check how many modules we have - long count = libhack_get_modules_count(handle, TRUE); + long count = libhack_get_modules_count(handle, filter); libhack_assert_or_return(count > 0, 0); HMODULE *modules = (HMODULE*)malloc(sizeof(HMODULE) * count); DWORD needed = 0; libhack_assert_or_return(modules, 0); - if(K32EnumProcessModulesEx(handle->hProcess, modules, count, &needed, LIST_MODULES_64BIT)) + if(K32EnumProcessModulesEx(handle->hProcess, modules, count, &needed, filter)) { - for(long i = 0; i < count; i++) { - if(K32GetModuleBaseNameA(handle->hProcess, modules[i], basename, sizeof(basename))) { - char *name = strlwr(basename); + for(long i = 0; i < count; i++) + { + if(K32GetModuleBaseNameA(handle->hProcess, modules[i], basename, sizeof(basename))) + { + strlwr(basename); - if(strncmp(name, module_name, strlen(module_name)) == 0) { + if(strnicmp(basename, module_name, strlen(module_name)) == 0) { addr = (DWORD64)modules[i]; break; } @@ -508,3 +627,53 @@ LIBHACK_API DWORD64 libhack_getsubmodule_addr64(struct libhack_handle *handle, c return addr; } + +static bool fIsWow64Process(HANDLE hProcess, DWORD *error) +{ + bool bIsWow64 = false; + pIsWow64Process fnIsWow64Process; + HMODULE kernel32 = GetModuleHandleA("kernel32"); + + libhack_assert_or_return(error, false); + + if(!kernel32) { + libhack_err("Failed to load kernel32.dll"); + *error = GetLastError(); + return false; + } + + fnIsWow64Process = (pIsWow64Process)GetProcAddress(kernel32, "IsWow64Process"); + + if(NULL != fnIsWow64Process) + { + if (!fnIsWow64Process(hProcess, &bIsWow64)) + { + // Set error + *error = GetLastError(); + + // Show debug message + libhack_err("Failed to call IsWow64Process"); + FreeLibrary(kernel32); + + return false; + } + } + + // Free resources + FreeLibrary(kernel32); + + // Set error code + *error = ERROR_SUCCESS; + + return bIsWow64; +} + +bool libhack_is64bit_process(struct libhack_handle *handle, DWORD *error) +{ + BOOL bWow64; + + // Call function + bWow64 = fIsWow64Process(handle->hProcess, error); + + return !bWow64; +} diff --git a/src/process.h b/src/process.h index 8dd7cc9..9345afc 100644 --- a/src/process.h +++ b/src/process.h @@ -21,14 +21,15 @@ extern "C" { #endif #include "init.h" +#include /** * @brief Opens the process specified when initializing library * * @param handle Handle to libhack previously opened by libhack_init - * @return BOOL TRUE on success FALSE otherwise + * @return bool true on success false otherwise */ -LIBHACK_API BOOL libhack_open_process(struct libhack_handle *handle); +LIBHACK_API bool libhack_open_process(struct libhack_handle *handle); /** * @brief Gets the process ID @@ -118,18 +119,18 @@ LIBHACK_API DWORD64 libhack_get_base_addr64(struct libhack_handle *handle); * @brief Determines if the previously opened process still up and running * * @param handle Handle to libhack - * @return bool TRUE if process is running FALSE otherwise + * @return bool true if process is running false otherwise */ -LIBHACK_API BOOL libhack_process_is_running(struct libhack_handle *handle); +LIBHACK_API bool libhack_process_is_running(struct libhack_handle *handle); /** * @brief Injects a DLL into opened process * * @param handle Handle to libhack returned by libhack_open() * @param dll_path Full path of dll to be injected - * @return BOOL TRUE on success FALSE on errors + * @return bool true on success false on errors */ -LIBHACK_API BOOL libhack_inject_dll(struct libhack_handle *handle, const char *dll_path); +LIBHACK_API bool libhack_inject_dll(struct libhack_handle *handle, const char *dll_path); /** * @brief Gets the address of a module loaded by process @@ -149,6 +150,15 @@ LIBHACK_API DWORD libhack_getsubmodule_addr(struct libhack_handle *handle, const */ LIBHACK_API DWORD64 libhack_getsubmodule_addr64(struct libhack_handle *handle, const char *module_name); +/** + * @brief Checks if a process is a x64 process + * + * @param handle Process handle (it must be opened first) + * @param errorCode Error code (will be 0 on success) + * @return LIBHACK_API bool true if process is a x64 process + */ +LIBHACK_API bool libhack_is64bit_process(struct libhack_handle *handle, DWORD *error); + #ifdef __cplusplus } #endif