diff options
Diffstat (limited to 'src/process64.h')
| -rw-r--r-- | src/process64.h | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/src/process64.h b/src/process64.h new file mode 100644 index 0000000..aa7a838 --- /dev/null +++ b/src/process64.h @@ -0,0 +1,267 @@ +//|_ _ _. _ ._ |_ _. _ | +//| | (/_ (_| \/ (/_ | | | | (_| (_ |< + +#pragma once +#include <Windows.h> +#include <TlHelp32.h> + +#include "ntutil.h" +#include "winintern.h" +#include "typedef.h" +#include "fnv.h" + +#include "conout.h" + + +struct MODULE_ENTRY { + U64 base; + U64 size; + STR<64> name; + FNV1A hash; +}; + +class PROCESS64 { +private: + HANDLE m_base{}; + U64 m_id{}; + char m_name[256]{}; + +private: + + +public: + PROCESS64( const char* name ) { + memset( m_name, 0, 256 ); + memcpy( m_name, name, strlen( name ) ); + }; + + HANDLE get_base() { return m_base; } + + I8 open() { + m_id = 0; + + const U32 PINFO_ALLOC_SIZE = 0x400000; + _SYSTEM_PROCESS_INFORMATION64* pinfo; + ULONG received_bytes; + + pinfo = (_SYSTEM_PROCESS_INFORMATION64*)VirtualAlloc( + 0, + PINFO_ALLOC_SIZE, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE + ); + + NTSTATUS64 status = nt_query_system_information64( + SystemProcessInformation, + pinfo, + PINFO_ALLOC_SIZE, + &received_bytes + ); + + if( status != STATUS_SUCCESS ) + return 0; + + wchar_t name_buffer[128]; + do { + if( pinfo->ImageName.Buffer ) { + nt_read_vm64( (HANDLE)-1, pinfo->ImageName.Buffer, name_buffer, 256 ); + STR<128> pname = u_widebyte_to_ansi( name_buffer ); + if( !strcmp( pname, m_name ) ) { + m_id = pinfo->UniqueProcessId; + break; + } + } + + pinfo = (decltype( pinfo ))( (U32)pinfo + pinfo->NextEntryOffset ); + } while( !!pinfo->NextEntryOffset ); + + VirtualFree( pinfo, PINFO_ALLOC_SIZE, MEM_FREE ); + + _OBJECT_ATTRIBUTES64 obj_attributes{}; + _CLIENT_ID_T<U64> cid; + + cid.UniqueProcess = (U64)( UlongToHandle( m_id ) ); + cid.UniqueThread = 0; + obj_attributes.Length = sizeof( obj_attributes ); + + status = nt_open_process64( + &m_base, + PROCESS_ALL_ACCESS, + &obj_attributes, + &cid + ); + + return status == STATUS_SUCCESS; + } + + U8 valid() { + PROCESS_BASIC_INFORMATION64 info; + + // 4 = ObjectHandleFlagInformation + NTSTATUS64 status = nt_query_information_process64( + m_base, ProcessBasicInformation, + &info, + sizeof(info), + 0 + ); + + if( status != STATUS_SUCCESS ) + return 0; + + return info.ExitStatus != 0; + } + + U32 get_module_size( U64 module_base ) { + IMAGE_NT_HEADERS64 nt_headers; + IMAGE_DOS_HEADER dos_header; + + read( module_base, &dos_header, sizeof( dos_header ) ); + read( module_base + dos_header.e_lfanew, &nt_headers, sizeof( nt_headers ) ); + + return nt_headers.OptionalHeader.SizeOfImage; + } + + VECTOR<MODULE_ENTRY> dump_modules() { + VECTOR<MODULE_ENTRY> ret; + PROCESS_BASIC_INFORMATION64 pbi; + ULONG pbi_len; + PEB64 peb; + NTSTATUS64 status; + + status = nt_query_information_process64( + m_base, + ProcessBasicInformation, + &pbi, + sizeof( PROCESS_BASIC_INFORMATION64 ), + &pbi_len + ); + + read( pbi.PebBaseAddress, &peb, sizeof( PEB64 ) ); + + PEB_LDR_DATA64 ldr; + read( peb.Ldr, &ldr, sizeof( ldr ) ); + + U64 root = ldr.InMemoryOrderModuleList.Flink; + for( U64 entry = read<U64>( root ); entry != root && !!entry; entry = read<U64>( entry ) ) { + _LDR_DATA_TABLE_ENTRY64_T ldr_entry; + read( entry, &ldr_entry, sizeof( ldr_entry ) ); + + if( !ldr_entry.FullDllName.Buffer ) + continue; + + wchar_t module_buffer[256]{}; + read( + ldr_entry.FullDllName.Buffer, + module_buffer, 256 * sizeof( wchar_t ) + ); + + STR<256> module_name = u_widebyte_to_ansi<256>( module_buffer ); + FNV1A module_hash = fnv1a( module_name ); + U64 module_base = ldr_entry.DllBase; + U64 module_size = ldr_entry.SizeOfImage; + + ret.push_back( { + module_base, + module_size, + module_name.data, + module_hash + } ); + } + + return ret; + } + + MODULE_ENTRY get_module64( FNV1A name ) { + std::vector< MODULE_ENTRY > modules = dump_modules(); + for( auto& it : modules ) { + if( it.hash == name ) + return it; + } + + return {}; + } + + U64 code_match( U64 module_base, const char* sig, U64 start = 0 ) { + U32 sig_length; + U8* sig_bytes = u_parse_signature( sig, &sig_length ); + if( !sig_bytes || sig_length <= 2 ) + return 0; + + U64 ret = code_match( module_base, sig_bytes, sig_length, start ); + + free( sig_bytes ); + return ret; + } + + U64 code_match( U64 module_base, U8* bytes, U64 length, U64 start = 0 ) { + MEMORY_BASIC_INFORMATION64 mbi{0}; + U32 module_size = get_module_size( module_base ); + if( start < module_base ) + start = module_base; + + U8* module_copy = (U8*)malloc( module_size ); + read( module_base, module_copy, module_size ); + + bool first = true; + + for( U64 off = start - module_base; off < module_size; off += mbi.RegionSize ) { + nt_query_vm64( m_base, module_base + off, MemoryRegionInfo, &mbi, sizeof( mbi ) ); + + if( mbi.State == MEM_FREE ) + continue; + + U64 mbi_address = mbi.BaseAddress - module_base; + U64 region_start = first? start - mbi.BaseAddress : 0; + for( U64 i = region_start; i < mbi.RegionSize - length; ++i ) { + if( u_binary_match( module_copy + mbi_address + i, bytes, length ) ) { + free( module_copy ); + return mbi.BaseAddress + i; + } + + first = false; + } + } + + free( module_copy ); + return 0; + } + + U64 get_id() { return m_id; } + + template < typename t > void write( U64 address, const t& value ) { + nt_write_vm64( m_base, address, (void*)&value, sizeof( t ) ); + } + + void write( U64 address, const void* buffer, U32 size ) { + nt_write_vm64( m_base, address, (void*)buffer, size ); + } + + template < typename t > t read( U64 address ) { + t buffer{}; + read( address, &buffer, sizeof( t ) ); + + return buffer; + } + + void read( U64 address, void* out, U32 size ) { + nt_read_vm64( m_base, address, out, size ); + } + + bool protect( U64 address, U32 size, ULONG protect ) { + assert( false ); + } + + U64 allocate( + U64 size, + ULONG protect = PAGE_EXECUTE_READWRITE, + ULONG alloc_type = MEM_COMMIT | MEM_RESERVE + ) { + U64 out{}; + NTSTATUS64 st = nt_allocate_vm64( m_base, &out, 0, &size, alloc_type, protect ); + if( st != STATUS_SUCCESS ) { + return 0; + } + + return out; + } +}; |
