Move defs to top of file, remove pointer-to-pointer, make RegexNeedle contain static-size arrays
This commit is contained in:
parent
72b39289d0
commit
8f51ee7e6d
|
@ -2,6 +2,89 @@
|
|||
#include "common_metapi.h"
|
||||
#include "../tiny-regex-c/re.h"
|
||||
|
||||
#ifndef __kernel_entry
|
||||
#define __kernel_entry
|
||||
#endif
|
||||
|
||||
typedef __kernel_entry NTSTATUS(WINAPI* NTQUERYINFORMATIONPROCESS) (HANDLE ProcessHandle, DWORD ProcessInformationClass, LPVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
|
||||
|
||||
typedef SIZE_T(WINAPI* VIRTUALQUERYEX) (HANDLE hProcess, LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength);
|
||||
|
||||
typedef BOOL(WINAPI* CLOSEHANDLE) (HANDLE hObject);
|
||||
|
||||
typedef HANDLE(WINAPI* OPENPROCESS) (DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
|
||||
|
||||
typedef FARPROC(WINAPI* GETPROCADDRESS) (HMODULE hModule, LPCSTR lpProcName);
|
||||
|
||||
// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FMemory%20Management%2FVirtual%20Memory%2FNtReadVirtualMemory.html
|
||||
// https://ntdoc.m417z.com/ntreadvirtualmemory
|
||||
typedef NTSTATUS(NTAPI* NTREADVIRTUALMEMORY) (HANDLE ProcessHandle, LPCVOID BaseAddress, LPVOID Buffer, SIZE_T NumberOfBytesToRead, PSIZE_T NumberOfBytesRead);
|
||||
|
||||
// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FMemory%20Management%2FVirtual%20Memory%2FMEMORY_INFORMATION_CLASS.html
|
||||
typedef enum _MEMORY_INFORMATION_CLASS {
|
||||
MemoryBasicInformation
|
||||
} MEMORY_INFORMATION_CLASS, * PMEMORY_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _UNICODE_STRING {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} UNICODE_STRING;
|
||||
typedef UNICODE_STRING* PUNICODE_STRING;
|
||||
typedef const UNICODE_STRING* PCUNICODE_STRING;
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_object_attributes
|
||||
typedef struct _OBJECT_ATTRIBUTES {
|
||||
ULONG Length;
|
||||
HANDLE RootDirectory;
|
||||
PUNICODE_STRING ObjectName;
|
||||
ULONG Attributes;
|
||||
PVOID SecurityDescriptor;
|
||||
PVOID SecurityQualityOfService;
|
||||
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
|
||||
|
||||
typedef struct _RTL_USER_PROCESS_PARAMETERS {
|
||||
BYTE Reserved1[16];
|
||||
PVOID Reserved2[10];
|
||||
UNICODE_STRING ImagePathName;
|
||||
UNICODE_STRING CommandLine;
|
||||
} RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS;
|
||||
|
||||
typedef
|
||||
VOID
|
||||
(NTAPI* PPS_POST_PROCESS_INIT_ROUTINE) (
|
||||
VOID
|
||||
);
|
||||
|
||||
typedef struct _PEB {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[1];
|
||||
PVOID Reserved3[2];
|
||||
PPEB_LDR_DATA Ldr;
|
||||
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
|
||||
BYTE Reserved4[104];
|
||||
PVOID Reserved5[52];
|
||||
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
|
||||
BYTE Reserved6[128];
|
||||
PVOID Reserved7[1];
|
||||
ULONG SessionId;
|
||||
} PEB, * PPEB;
|
||||
|
||||
typedef struct _PROCESS_BASIC_INFORMATION {
|
||||
PVOID Reserved1;
|
||||
PPEB PebBaseAddress;
|
||||
PVOID Reserved2[2];
|
||||
ULONG_PTR UniqueProcessId;
|
||||
PVOID Reserved3;
|
||||
} PROCESS_BASIC_INFORMATION;
|
||||
typedef PROCESS_BASIC_INFORMATION* PPROCESS_BASIC_INFORMATION;
|
||||
|
||||
typedef enum _PROCESSINFOCLASS {
|
||||
ProcessBasicInformation = 0,
|
||||
ProcessWow64Information = 26
|
||||
} PROCESSINFOCLASS;
|
||||
|
||||
/*!
|
||||
* @brief Allocates memory in the context of the supplied process.
|
||||
* @remark The
|
||||
|
@ -341,89 +424,6 @@ DWORD request_sys_process_memory_unlock(Remote *remote, Packet *packet)
|
|||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef __kernel_entry
|
||||
#define __kernel_entry
|
||||
#endif
|
||||
|
||||
typedef __kernel_entry NTSTATUS(WINAPI* NTQUERYINFORMATIONPROCESS) (HANDLE ProcessHandle, DWORD ProcessInformationClass, LPVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
|
||||
|
||||
typedef SIZE_T(WINAPI* VIRTUALQUERYEX) (HANDLE hProcess, LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength);
|
||||
|
||||
typedef BOOL(WINAPI* CLOSEHANDLE) (HANDLE hObject);
|
||||
|
||||
typedef HANDLE(WINAPI* OPENPROCESS) (DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwProcessId);
|
||||
|
||||
typedef FARPROC(WINAPI* GETPROCADDRESS) (HMODULE hModule, LPCSTR lpProcName);
|
||||
|
||||
// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FMemory%20Management%2FVirtual%20Memory%2FNtReadVirtualMemory.html
|
||||
// https://ntdoc.m417z.com/ntreadvirtualmemory
|
||||
typedef NTSTATUS(NTAPI* NTREADVIRTUALMEMORY) (HANDLE ProcessHandle, LPCVOID BaseAddress, LPVOID Buffer, SIZE_T NumberOfBytesToRead, PSIZE_T NumberOfBytesRead);
|
||||
|
||||
// http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FMemory%20Management%2FVirtual%20Memory%2FMEMORY_INFORMATION_CLASS.html
|
||||
typedef enum _MEMORY_INFORMATION_CLASS {
|
||||
MemoryBasicInformation
|
||||
} MEMORY_INFORMATION_CLASS, * PMEMORY_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _UNICODE_STRING {
|
||||
USHORT Length;
|
||||
USHORT MaximumLength;
|
||||
PWSTR Buffer;
|
||||
} UNICODE_STRING;
|
||||
typedef UNICODE_STRING* PUNICODE_STRING;
|
||||
typedef const UNICODE_STRING* PCUNICODE_STRING;
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/ntdef/ns-ntdef-_object_attributes
|
||||
typedef struct _OBJECT_ATTRIBUTES {
|
||||
ULONG Length;
|
||||
HANDLE RootDirectory;
|
||||
PUNICODE_STRING ObjectName;
|
||||
ULONG Attributes;
|
||||
PVOID SecurityDescriptor;
|
||||
PVOID SecurityQualityOfService;
|
||||
} OBJECT_ATTRIBUTES, * POBJECT_ATTRIBUTES;
|
||||
|
||||
typedef struct _RTL_USER_PROCESS_PARAMETERS {
|
||||
BYTE Reserved1[16];
|
||||
PVOID Reserved2[10];
|
||||
UNICODE_STRING ImagePathName;
|
||||
UNICODE_STRING CommandLine;
|
||||
} RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS;
|
||||
|
||||
typedef
|
||||
VOID
|
||||
(NTAPI* PPS_POST_PROCESS_INIT_ROUTINE) (
|
||||
VOID
|
||||
);
|
||||
|
||||
typedef struct _PEB {
|
||||
BYTE Reserved1[2];
|
||||
BYTE BeingDebugged;
|
||||
BYTE Reserved2[1];
|
||||
PVOID Reserved3[2];
|
||||
PPEB_LDR_DATA Ldr;
|
||||
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
|
||||
BYTE Reserved4[104];
|
||||
PVOID Reserved5[52];
|
||||
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
|
||||
BYTE Reserved6[128];
|
||||
PVOID Reserved7[1];
|
||||
ULONG SessionId;
|
||||
} PEB, * PPEB;
|
||||
|
||||
typedef struct _PROCESS_BASIC_INFORMATION {
|
||||
PVOID Reserved1;
|
||||
PPEB PebBaseAddress;
|
||||
PVOID Reserved2[2];
|
||||
ULONG_PTR UniqueProcessId;
|
||||
PVOID Reserved3;
|
||||
} PROCESS_BASIC_INFORMATION;
|
||||
typedef PROCESS_BASIC_INFORMATION* PPROCESS_BASIC_INFORMATION;
|
||||
|
||||
typedef enum _PROCESSINFOCLASS {
|
||||
ProcessBasicInformation = 0,
|
||||
ProcessWow64Information = 26
|
||||
} PROCESSINFOCLASS;
|
||||
|
||||
BOOL can_read_memory(DWORD memory_protect)
|
||||
{
|
||||
const int page_execute_read = 0x20;
|
||||
|
@ -437,14 +437,10 @@ BOOL can_read_memory(DWORD memory_protect)
|
|||
memory_protect == page_readwrite;
|
||||
}
|
||||
|
||||
// In order to be able to regex null-butes, we need to store the length explicitly, so that null-bytes aren't being treated as the end of a string.
|
||||
struct regex_needle
|
||||
{
|
||||
char* raw_needle_buffer;
|
||||
size_t length;
|
||||
regex_t* compiled_needle;
|
||||
unsigned char* char_buf;
|
||||
};
|
||||
typedef struct {
|
||||
re_t compiled_regex[MAX_REGEXP_OBJECTS];
|
||||
unsigned char buffer[MAX_CHAR_CLASS_LEN]; // Used for character strings when "[]" is used.
|
||||
} RegexNeedle;
|
||||
|
||||
#define NEEDLES_MAX (size_t)5
|
||||
#define MEMORY_BUFFER_SIZE (size_t)(64 * 1024 * 1024)
|
||||
|
@ -452,116 +448,25 @@ struct regex_needle
|
|||
/// <summary>
|
||||
/// Add the needle results to a packet. This automatically inserts each result into a new group. Returns ERROR_SUCCESS on success, or 1 on failure.
|
||||
/// </summary>
|
||||
/// <param name="out">The packet to insert the needle goup into</param>
|
||||
/// <param name="packet">The packet to insert the needle group into</param>
|
||||
/// <returns>ERROR_SUCCESS on success, else non-zero</returns>
|
||||
NTSTATUS add_needle_results_to_packet(Packet** out, const char* memory_buffer_ptr, size_t match_length, size_t match_address, size_t memory_base_address, size_t memory_region_size)
|
||||
NTSTATUS add_needle_results_to_packet(Packet* packet, const unsigned char* memory_buffer_ptr, size_t match_length, size_t match_address, size_t memory_base_address, size_t memory_region_size)
|
||||
{
|
||||
if (out == NULL || memory_buffer_ptr == NULL) { return ERROR_INVALID_PARAMETER; }
|
||||
if (packet == NULL || memory_buffer_ptr == NULL) { return ERROR_INVALID_PARAMETER; }
|
||||
|
||||
dprintf("[MEM SEARCH] Creating results group");
|
||||
|
||||
Packet* search_results = met_api->packet.create_group();
|
||||
if (search_results == NULL) { dprintf("[MEM SEARCH] Could not create search result group"); return ERROR_OUTOFMEMORY; }
|
||||
|
||||
dprintf("[MEM SEARCH] Adding results to packet group");
|
||||
|
||||
dprintf("[MEM SEARCH] Adding Match bytes");
|
||||
// Note: This raw data needs to be read from the buffer we copied. Trying to read it from mem.BaseAddress directly will make us crash.
|
||||
met_api->packet.add_tlv_raw(search_results, TLV_TYPE_MEMORY_SEARCH_MATCH_STR, (LPVOID)memory_buffer_ptr, (DWORD)match_length + 1);
|
||||
|
||||
dprintf("[MEM SEARCH] Adding Match address");
|
||||
met_api->packet.add_tlv_qword(search_results, TLV_TYPE_MEMORY_SEARCH_MATCH_ADDR, match_address);
|
||||
|
||||
dprintf("[MEM SEARCH] Adding Region base address");
|
||||
met_api->packet.add_tlv_qword(search_results, TLV_TYPE_MEMORY_SEARCH_START_ADDR, memory_base_address);
|
||||
|
||||
dprintf("[MEM SEARCH] Adding Region size");
|
||||
met_api->packet.add_tlv_qword(search_results, TLV_TYPE_MEMORY_SEARCH_SECT_LEN, memory_region_size);
|
||||
|
||||
dprintf("[MEM SEARCH] Adding Match Length");
|
||||
met_api->packet.add_tlv_uint(search_results, TLV_TYPE_MEMORY_SEARCH_MATCH_LEN, (UINT)match_length);
|
||||
|
||||
dprintf("[MEM SEARCH] Adding Group");
|
||||
met_api->packet.add_group(*out, TLV_TYPE_MEMORY_SEARCH_RESULTS, search_results);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compile a regular expression in-place.
|
||||
/// </summary>
|
||||
/// <param name="in_out">A pointer to a regular expression needle struct.</param>
|
||||
/// <returns>ERROR_SUCCESS on success, ERROR_INVALID_PARAMETER when provided with a null pointer or the regular expression failed to compile</returns>
|
||||
NTSTATUS re_compile_inplace(struct regex_needle** in_out)
|
||||
{
|
||||
if (in_out == NULL) { return ERROR_INVALID_PARAMETER; }
|
||||
const int compile_result = re_compile((*in_out)->raw_needle_buffer, (*in_out)->length, MAX_REGEXP_OBJECTS, MAX_CHAR_CLASS_LEN, &(*in_out)->compiled_needle, &(*in_out)->char_buf);
|
||||
if (compile_result != ERROR_SUCCESS) { return ERROR_INVALID_PARAMETER; }
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up a regular expression needle from a TLV.
|
||||
/// </summary>
|
||||
/// <param name="needle_buffer_tlv">- Pointer to the needle TLV received from the server containing the needle buffer</param>
|
||||
/// <param name="out">- The compiled needle</param>
|
||||
/// <returns>ERROR_SUCCESS on success, non-zero on failure</returns>
|
||||
NTSTATUS setup_needle_from_tlv(const Tlv* needle_buffer_tlv, struct regex_needle** out)
|
||||
{
|
||||
// The header contains a null-terminator which we do not need.
|
||||
dprintf("[MEM SEARCH] Getting needle length");
|
||||
const size_t needle_length = needle_buffer_tlv->header.length - 1;
|
||||
if (needle_length == 0) { dprintf("[MEM SEARCH] Got a needle length of 0"); return ERROR_INVALID_PARAMETER; }
|
||||
|
||||
(*out)->length = needle_length;
|
||||
dprintf("[MEM SEARCH] Allocating memory for needle buffer");
|
||||
(*out)->raw_needle_buffer = (char*)malloc(needle_length * sizeof(char));
|
||||
if ((*out)->raw_needle_buffer == NULL) { dprintf("[MEM SEARCH] Could not allocate memory for raw needle buffer"); return ERROR_OUTOFMEMORY; }
|
||||
|
||||
dprintf("[MEM SEARCH] Copying TLV buffer to needle");
|
||||
memcpy((*out)->raw_needle_buffer, (char*)needle_buffer_tlv->buffer, needle_length);
|
||||
|
||||
dprintf("[MEM SEARCH] Allocating memory for a compiled needle");
|
||||
(*out)->compiled_needle = (regex_t*)malloc(MAX_REGEXP_OBJECTS * sizeof(struct regex_t));
|
||||
if ((*out)->compiled_needle == NULL) { dprintf("[MEM SEARCH] Unable to malloc memory for a compiled needle"); return ERROR_OUTOFMEMORY; }
|
||||
|
||||
dprintf("[MEM SEARCH] Allocating memory for a char buffer");
|
||||
(*out)->char_buf = (unsigned char*)malloc(MAX_CHAR_CLASS_LEN * sizeof(unsigned char));
|
||||
if ((*out)->char_buf == NULL) { dprintf("[MEM SEARCH] Unable to malloc memory for a char buffer"); return ERROR_OUTOFMEMORY; }
|
||||
|
||||
dprintf("[MEM SEARCH] Compiling needle: %.*s", needle_length, (char*)needle_buffer_tlv->buffer);
|
||||
const NTSTATUS compile_result = re_compile_inplace(&(*out));
|
||||
if (compile_result != ERROR_SUCCESS)
|
||||
{ dprintf("[MEM SEARCH] Failed to compile needle"); return ERROR_INVALID_PARAMETER; }
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS cleanup_needle(struct regex_needle** in)
|
||||
{
|
||||
if (in == NULL || *in == NULL) { return ERROR_INVALID_PARAMETER; }
|
||||
|
||||
if ((*in)->raw_needle_buffer != NULL)
|
||||
{
|
||||
dprintf("[MEM SEARCH] Freeing needle buffer");
|
||||
free((*in)->raw_needle_buffer);
|
||||
}
|
||||
|
||||
if ((*in)->char_buf != NULL)
|
||||
{
|
||||
dprintf("[MEM SEARCH] Freeing char buf");
|
||||
free((*in)->char_buf);
|
||||
}
|
||||
|
||||
if ((*in)->compiled_needle != NULL)
|
||||
{
|
||||
dprintf("[MEM SEARCH] Freeing compiled needle");
|
||||
free((*in)->compiled_needle);
|
||||
}
|
||||
|
||||
dprintf("[MEM SEARCH] Freeing regex needle.");
|
||||
free((*in));
|
||||
met_api->packet.add_group(packet, TLV_TYPE_MEMORY_SEARCH_RESULTS, search_results);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
@ -575,7 +480,7 @@ static CLOSEHANDLE fCloseHandle = NULL;
|
|||
static VIRTUALQUERYEX fVirtualQueryEx = NULL;
|
||||
static NTREADVIRTUALMEMORY fNtReadVirtualMemory = NULL;
|
||||
|
||||
BOOL setup_handles()
|
||||
NTSTATUS setup_handles()
|
||||
{
|
||||
if ((hKernel32 = GetModuleHandleA("kernel32.dll")) == NULL) { dprintf("[MEM SEARCH] Could not get kernel32.dll handle"); return ERROR_INVALID_HANDLE; }
|
||||
|
||||
|
@ -606,29 +511,24 @@ DWORD request_sys_process_memory_search(Remote* remote, Packet* packet)
|
|||
{
|
||||
Packet* response = met_api->packet.create_response(packet);
|
||||
DWORD result = ERROR_SUCCESS;
|
||||
char* buffer = NULL;
|
||||
unsigned char* memory_buffer = NULL;
|
||||
size_t needle_enum_index = 0;
|
||||
HANDLE process_handle = NULL;
|
||||
struct regex_needle* regex_needles[NEEDLES_MAX];
|
||||
RegexNeedle regex_needles[NEEDLES_MAX] = { NULL };
|
||||
|
||||
dprintf("[MEM SEARCH] Getting PID");
|
||||
const DWORD pid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PID);
|
||||
if (pid == 0) { result = ERROR_INVALID_PARAMETER; goto done; }
|
||||
dprintf("[MEM SEARCH] Searching PID: %lu", pid);
|
||||
|
||||
Tlv needle_buffer_tlv = { 0 };
|
||||
while (needle_enum_index < NEEDLES_MAX && met_api->packet.enum_tlv(packet, (DWORD)needle_enum_index, TLV_TYPE_MEMORY_SEARCH_NEEDLE, &needle_buffer_tlv) == ERROR_SUCCESS)
|
||||
Tlv needle_tlv = { 0 };
|
||||
while (needle_enum_index < NEEDLES_MAX && met_api->packet.enum_tlv(packet, (DWORD)needle_enum_index, TLV_TYPE_MEMORY_SEARCH_NEEDLE, &needle_tlv) == ERROR_SUCCESS)
|
||||
{
|
||||
dprintf("[MEM SEARCH] Allocating %u bytes of memory for regex needle", sizeof(struct regex_needle));
|
||||
regex_needles[needle_enum_index] = (struct regex_needle*)malloc(sizeof(struct regex_needle));
|
||||
if (regex_needles[needle_enum_index] == NULL) { dprintf("[MEM SEARCH] Could not allocate memory for regex needle"); result = ERROR_OUTOFMEMORY; goto done; }
|
||||
|
||||
dprintf("[MEM SEARCH] Setting up needle from TLV");
|
||||
const NTSTATUS needle_setup_result = setup_needle_from_tlv(&needle_buffer_tlv, ®ex_needles[needle_enum_index]);
|
||||
if (needle_setup_result != ERROR_SUCCESS)
|
||||
dprintf("[MEM SEARCH] Compiling needle regex from TLV");
|
||||
const int result = re_compile(needle_tlv.buffer, needle_tlv.header.length - 1, (re_t)®ex_needles[needle_enum_index].compiled_regex, (unsigned char*)®ex_needles[needle_enum_index].buffer);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
dprintf("[MEM SEARCH] Failed to setup needle from TLV packet");
|
||||
result = needle_setup_result;
|
||||
dprintf("[MEM SEARCH] Failed to setup compile needle regex from TLV packet");
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
@ -642,8 +542,11 @@ DWORD request_sys_process_memory_search(Remote* remote, Packet* packet)
|
|||
const size_t current_max_match_length = max_match_length;
|
||||
|
||||
dprintf("[MEM SEARCH] Getting handles & proc addresses");
|
||||
const NTSTATUS setup_handles_result = setup_handles();
|
||||
if (setup_handles_result != ERROR_SUCCESS) { dprintf("[MEM SEARCH] Could not set up all necessary handles & proc addresses"); result = setup_handles_result; goto done; }
|
||||
if ((result = setup_handles()) != ERROR_SUCCESS)
|
||||
{
|
||||
dprintf("[MEM SEARCH] Could not set up all necessary handles & proc addresses");
|
||||
goto done;
|
||||
}
|
||||
|
||||
const DWORD process_vm_read = 0x0010;
|
||||
const DWORD process_query_information = 0x0400;
|
||||
|
@ -655,8 +558,8 @@ DWORD request_sys_process_memory_search(Remote* remote, Packet* packet)
|
|||
|
||||
MEMORY_BASIC_INFORMATION mem = { 0 };
|
||||
dprintf("[MEM SEARCH] Allocating buffer for storing process memory");
|
||||
buffer = (char*)malloc(MEMORY_BUFFER_SIZE);
|
||||
if (buffer == NULL) { dprintf("[MEM SEARCH] Could not allocate memory buffer"); result = ERROR_OUTOFMEMORY; goto done; }
|
||||
memory_buffer = (unsigned char*)malloc(MEMORY_BUFFER_SIZE * sizeof(unsigned char));
|
||||
if (memory_buffer == NULL) { dprintf("[MEM SEARCH] Could not allocate memory buffer"); result = ERROR_OUTOFMEMORY; goto done; }
|
||||
|
||||
for (size_t current_ptr = 0; fVirtualQueryEx(process_handle, (LPCVOID)current_ptr, &mem, sizeof(mem)); current_ptr += mem.RegionSize)
|
||||
{
|
||||
|
@ -670,15 +573,19 @@ DWORD request_sys_process_memory_search(Remote* remote, Packet* packet)
|
|||
while (mem.RegionSize > memory_region_offset)
|
||||
{
|
||||
const size_t leftover_bytes = mem.RegionSize - memory_region_offset;
|
||||
const size_t bytes_to_read = min(leftover_bytes, MEMORY_BUFFER_SIZE);
|
||||
const size_t bytes_to_read = min(leftover_bytes, MEMORY_BUFFER_SIZE * sizeof(unsigned char));
|
||||
dprintf("[MEM SEARCH] Leftover Bytes count: %llu", leftover_bytes);
|
||||
dprintf("[MEM SEARCH] Bytes to read: %llu", bytes_to_read);
|
||||
size_t bytes_read = 0;
|
||||
|
||||
const size_t read_address = (size_t)mem.BaseAddress + memory_region_offset;
|
||||
// Note: This will read up to a maximum of bytes_to_read OR to the end of the memory region if the end of it has been reached.
|
||||
const NTSTATUS read_virtual_memory_status = fNtReadVirtualMemory(process_handle, (LPCVOID)read_address, buffer, bytes_to_read, &bytes_read);
|
||||
if (read_virtual_memory_status != ERROR_SUCCESS) { dprintf("[MEM SEARCH] Failed to read some virtual memory for process, skipping %u bytes", bytes_to_read); memory_region_offset += bytes_to_read; continue; }
|
||||
if (fNtReadVirtualMemory(process_handle, (LPCVOID)read_address, memory_buffer, bytes_to_read, &bytes_read) != ERROR_SUCCESS)
|
||||
{
|
||||
dprintf("[MEM SEARCH] Failed to read some virtual memory for process, skipping %u bytes", bytes_to_read);
|
||||
memory_region_offset += bytes_to_read;
|
||||
continue;
|
||||
}
|
||||
|
||||
dprintf("[MEM SEARCH] Read %llu bytes", bytes_read);
|
||||
// Note: Increment the offset so that we aren't stuck in an infinite loop, trying to read zero bytes from the same pointer.
|
||||
|
@ -692,10 +599,10 @@ DWORD request_sys_process_memory_search(Remote* remote, Packet* packet)
|
|||
|
||||
do
|
||||
{
|
||||
const char* current_buffer_ptr = buffer + current_buffer_offset;
|
||||
const unsigned char* current_buffer_ptr = memory_buffer + current_buffer_offset;
|
||||
const size_t bytes_to_regex = bytes_read - current_buffer_offset;
|
||||
|
||||
result = re_matchp(regex_needles[current_needle_index]->compiled_needle, current_buffer_ptr, bytes_to_regex, &match_length);
|
||||
result = re_matchp((re_t)®ex_needles[current_needle_index].compiled_regex, current_buffer_ptr, bytes_to_regex, &match_length);
|
||||
|
||||
if (result != -1)
|
||||
{
|
||||
|
@ -712,9 +619,11 @@ DWORD request_sys_process_memory_search(Remote* remote, Packet* packet)
|
|||
|
||||
// TODO: Add a workaround for match length to the regex itself, allowing the regex engine to stop matching once an upper limit has been reached.
|
||||
const size_t current_match_length = min(max_match_length, match_length);
|
||||
const char* memory_buffer_ptr = buffer + current_buffer_offset + result;
|
||||
const NTSTATUS add_needles_result = add_needle_results_to_packet(&response, memory_buffer_ptr, current_match_length, match_address, (size_t)mem.BaseAddress, mem.RegionSize);
|
||||
if (add_needles_result != ERROR_SUCCESS) { dprintf("[MEM SEARCH] Adding search results to packet was not successful"); }
|
||||
const unsigned char* memory_buffer_ptr = memory_buffer + current_buffer_offset + result;
|
||||
if (add_needle_results_to_packet(response, memory_buffer_ptr, current_match_length, match_address, (size_t)mem.BaseAddress, mem.RegionSize) != ERROR_SUCCESS)
|
||||
{
|
||||
dprintf("[MEM SEARCH] Adding search results to packet was not successful");
|
||||
}
|
||||
|
||||
current_buffer_offset += (result + current_match_length);
|
||||
}
|
||||
|
@ -731,16 +640,9 @@ DWORD request_sys_process_memory_search(Remote* remote, Packet* packet)
|
|||
|
||||
done:
|
||||
dprintf("[MEM SEARCH] Memory Search complete.");
|
||||
if (buffer != NULL) { dprintf("[MEM SEARCH] Freeing process memory buffer."); free(buffer); }
|
||||
if (memory_buffer != NULL) { dprintf("[MEM SEARCH] Freeing process memory buffer."); free(memory_buffer); }
|
||||
if (process_handle != NULL) { dprintf("[MEM SEARCH] Closing process handle."); fCloseHandle(process_handle); }
|
||||
|
||||
dprintf("[MEM SEARCH] Cleaning up needles");
|
||||
for (size_t i = 0; i < needle_enum_index; i++)
|
||||
{
|
||||
const NTSTATUS cleanup_result = cleanup_needle(®ex_needles[i]);
|
||||
if (cleanup_result == ERROR_INVALID_PARAMETER) { dprintf("[MEM SEARCH] Could not clean up needle"); }
|
||||
}
|
||||
|
||||
dprintf("[MEM SEARCH] Transmitting response");
|
||||
met_api->packet.transmit_response(result, remote, response);
|
||||
return ERROR_SUCCESS;
|
||||
|
|
|
@ -62,7 +62,7 @@ int re_matchp(re_t pattern, const char* text, size_t text_length, size_t* matchl
|
|||
return ((matchpattern(&pattern[1], text, text_length, 0, matchlength)) ? 0 : -1);
|
||||
}
|
||||
|
||||
size_t idx = -1;
|
||||
int idx = -1;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -70,18 +70,16 @@ int re_matchp(re_t pattern, const char* text, size_t text_length, size_t* matchl
|
|||
|
||||
if (matchpattern(pattern, text, text_length, idx, matchlength))
|
||||
{
|
||||
return (int)idx;
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
while (idx < text_length);
|
||||
while ((size_t)idx < text_length);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int re_compile(const char* pattern, size_t pattern_length, size_t max_regex_objects, size_t max_char_class_len, re_t* out_compiled, unsigned char** out_ccl)
|
||||
int re_compile(const char* pattern, size_t pattern_length, re_t compiled_regex, unsigned char* regex_char_buffer)
|
||||
{
|
||||
if (out_compiled == NULL || out_ccl == NULL) { return 1; }
|
||||
|
||||
int ccl_bufidx = 1;
|
||||
|
||||
char c; /* current char in pattern */
|
||||
|
@ -95,13 +93,13 @@ int re_compile(const char* pattern, size_t pattern_length, size_t max_regex_obje
|
|||
switch (c)
|
||||
{
|
||||
/* Meta-characters: */
|
||||
case '^': { (*out_compiled)[j].type = BEGIN; } break;
|
||||
case '$': { (*out_compiled)[j].type = END; } break;
|
||||
case '.': { (*out_compiled)[j].type = DOT; } break;
|
||||
case '*': { (*out_compiled)[j].type = STAR; } break;
|
||||
case '+': { (*out_compiled)[j].type = PLUS; } break;
|
||||
case '?': { (*out_compiled)[j].type = QUESTIONMARK; } break;
|
||||
/* case '|': { re_compiled[j].type = BRANCH; } break; <-- not working properly */
|
||||
case '^': { compiled_regex[j].type = BEGIN; } break;
|
||||
case '$': { compiled_regex[j].type = END; } break;
|
||||
case '.': { compiled_regex[j].type = DOT; } break;
|
||||
case '*': { compiled_regex[j].type = STAR; } break;
|
||||
case '+': { compiled_regex[j].type = PLUS; } break;
|
||||
case '?': { compiled_regex[j].type = QUESTIONMARK; } break;
|
||||
/* case '|': { compiled_regex[j].type = BRANCH; } break; <-- not working properly */
|
||||
|
||||
/* Escaped character-classes (\s \w ...): */
|
||||
case '\\':
|
||||
|
@ -114,25 +112,25 @@ int re_compile(const char* pattern, size_t pattern_length, size_t max_regex_obje
|
|||
switch (pattern[i])
|
||||
{
|
||||
/* Meta-character: */
|
||||
case 'd': { (*out_compiled)[j].type = DIGIT; } break;
|
||||
case 'D': { (*out_compiled)[j].type = NOT_DIGIT; } break;
|
||||
case 'w': { (*out_compiled)[j].type = ALPHA; } break;
|
||||
case 'W': { (*out_compiled)[j].type = NOT_ALPHA; } break;
|
||||
case 's': { (*out_compiled)[j].type = WHITESPACE; } break;
|
||||
case 'S': { (*out_compiled)[j].type = NOT_WHITESPACE; } break;
|
||||
case 'd': { compiled_regex[j].type = DIGIT; } break;
|
||||
case 'D': { compiled_regex[j].type = NOT_DIGIT; } break;
|
||||
case 'w': { compiled_regex[j].type = ALPHA; } break;
|
||||
case 'W': { compiled_regex[j].type = NOT_ALPHA; } break;
|
||||
case 's': { compiled_regex[j].type = WHITESPACE; } break;
|
||||
case 'S': { compiled_regex[j].type = NOT_WHITESPACE; } break;
|
||||
|
||||
/* Escaped character, e.g. '.' or '$' */
|
||||
default:
|
||||
{
|
||||
(*out_compiled)[j].type = CHAR_RE;
|
||||
(*out_compiled)[j].u.ch = pattern[i];
|
||||
compiled_regex[j].type = CHAR_RE;
|
||||
compiled_regex[j].u.ch = pattern[i];
|
||||
} break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(*out_compiled)[j].type = CHAR_RE;
|
||||
(*out_compiled)[j].u.ch = pattern[i];
|
||||
compiled_regex[j].type = CHAR_RE;
|
||||
compiled_regex[j].u.ch = pattern[i];
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -145,7 +143,7 @@ int re_compile(const char* pattern, size_t pattern_length, size_t max_regex_obje
|
|||
/* Look-ahead to determine if negated */
|
||||
if (pattern[i + 1] == '^')
|
||||
{
|
||||
(*out_compiled)[j].type = INV_CHAR_CLASS;
|
||||
compiled_regex[j].type = INV_CHAR_CLASS;
|
||||
i += 1; /* Increment i to avoid including '^' in the char-buffer */
|
||||
if (i + 1 == (int)pattern_length) /* incomplete pattern, missing non-zero char after '^' */
|
||||
{
|
||||
|
@ -154,7 +152,7 @@ int re_compile(const char* pattern, size_t pattern_length, size_t max_regex_obje
|
|||
}
|
||||
else
|
||||
{
|
||||
(*out_compiled)[j].type = CHAR_CLASS;
|
||||
compiled_regex[j].type = CHAR_CLASS;
|
||||
}
|
||||
|
||||
/* Copy characters inside [..] to buffer */
|
||||
|
@ -172,14 +170,14 @@ int re_compile(const char* pattern, size_t pattern_length, size_t max_regex_obje
|
|||
{
|
||||
return 1;
|
||||
}
|
||||
(*out_ccl)[ccl_bufidx++] = pattern[i++];
|
||||
regex_char_buffer[ccl_bufidx++] = pattern[i++];
|
||||
}
|
||||
else if (ccl_bufidx >= MAX_CHAR_CLASS_LEN)
|
||||
{
|
||||
//fputs("exceeded internal buffer!\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
(*out_ccl)[ccl_bufidx++] = pattern[i];
|
||||
regex_char_buffer[ccl_bufidx++] = pattern[i];
|
||||
}
|
||||
if (ccl_bufidx >= MAX_CHAR_CLASS_LEN)
|
||||
{
|
||||
|
@ -188,15 +186,15 @@ int re_compile(const char* pattern, size_t pattern_length, size_t max_regex_obje
|
|||
return 1;
|
||||
}
|
||||
/* Null-terminate string end */
|
||||
(*out_ccl)[ccl_bufidx++] = 0;
|
||||
(*out_compiled)[j].u.ccl = &(*out_ccl)[buf_begin];
|
||||
regex_char_buffer[ccl_bufidx++] = 0;
|
||||
compiled_regex[j].u.ccl = ®ex_char_buffer[buf_begin];
|
||||
} break;
|
||||
|
||||
/* Other characters: */
|
||||
default:
|
||||
{
|
||||
(*out_compiled)[j].type = CHAR_RE;
|
||||
(*out_compiled)[j].u.ch = c;
|
||||
compiled_regex[j].type = CHAR_RE;
|
||||
compiled_regex[j].u.ch = c;
|
||||
} break;
|
||||
}
|
||||
|
||||
|
@ -204,7 +202,7 @@ int re_compile(const char* pattern, size_t pattern_length, size_t max_regex_obje
|
|||
j += 1;
|
||||
}
|
||||
/* 'UNUSED' is a sentinel used to indicate end-of-pattern */
|
||||
(*out_compiled)[j].type = UNUSED;
|
||||
compiled_regex[j].type = UNUSED;
|
||||
|
||||
return 0; // ERROR_SUCCESS
|
||||
}
|
||||
|
@ -364,7 +362,7 @@ static int matchstar(regex_t p, regex_t* pattern, const char* text, size_t text_
|
|||
const char* prepoint = text;
|
||||
while ((text_offset < text_length) && matchone(p, text[text_offset]))
|
||||
{
|
||||
text_offset++;
|
||||
text_offset++;
|
||||
(*matchlength)++;
|
||||
}
|
||||
while (&text[text_offset] >= prepoint)
|
||||
|
@ -383,7 +381,7 @@ static int matchplus(regex_t p, regex_t* pattern, const char* text, size_t text_
|
|||
const char* prepoint = text;
|
||||
while ((text_offset < text_length) && matchone(p, text[text_offset]))
|
||||
{
|
||||
text_offset++;
|
||||
text_offset++;
|
||||
(*matchlength)++;
|
||||
}
|
||||
while (text > prepoint)
|
||||
|
|
|
@ -62,7 +62,7 @@ typedef struct regex_t* re_t;
|
|||
int re_matchp(re_t pattern, const char* text, size_t text_length, size_t* matchlength);
|
||||
|
||||
/* Compile a regular expression in-place, allowing for multiple needles to be compiled without the usage of a static buffer. Returns ERROR_SUCCESS (0) on success, else 1. */
|
||||
int re_compile(const char* pattern, size_t pattern_length, size_t max_regex_objects, size_t max_char_class_len, re_t* out_compiled, unsigned char** out_ccl);
|
||||
int re_compile(const char* pattern, size_t pattern_length, re_t compiled_regex, unsigned char* regex_char_buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue