summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2013-03-09 15:28:20 +0100
committermanuel <manuel@mausz.at>2013-03-09 15:28:20 +0100
commitedc56b1c98beac5f19a273695f66b8bc58722938 (patch)
tree423a4da38f33336ebfad893eb416d2475e3447ba
parentc23c702370ebe26ed7ba97980f80935c9aa37515 (diff)
downloadsteamcmd-edc56b1c98beac5f19a273695f66b8bc58722938.tar.gz
steamcmd-edc56b1c98beac5f19a273695f66b8bc58722938.tar.bz2
steamcmd-edc56b1c98beac5f19a273695f66b8bc58722938.zip
add signature scanner
-rw-r--r--ModuleScanner.cpp99
-rw-r--r--ModuleScanner.h18
-rw-r--r--sigscan.cpp124
-rw-r--r--sigscan.h64
4 files changed, 305 insertions, 0 deletions
diff --git a/ModuleScanner.cpp b/ModuleScanner.cpp
new file mode 100644
index 0000000..831f87a
--- /dev/null
+++ b/ModuleScanner.cpp
@@ -0,0 +1,99 @@
1#include "ModuleScanner.h"
2#include <stdlib.h>
3#include <string.h>
4#include <elf.h>
5#include <dlfcn.h>
6
7CModuleScanner::CModuleScanner(void *addr)
8 : m_addr(addr)
9{}
10
11void *CModuleScanner::FindSignature(const char *sig, const char *pattern)
12{
13 DynLibInfo lib;
14 bool found;
15 char *ptr, *end;
16 size_t len = strlen(pattern);
17
18 memset(&lib, 0, sizeof(DynLibInfo));
19
20 if (!GetLibraryInfo(m_addr, lib))
21 return NULL;
22
23 ptr = reinterpret_cast<char *>(lib.baseAddress);
24 end = ptr + lib.memorySize;
25
26 while (ptr < end)
27 {
28 found = true;
29 for (register size_t i = 0; i < len; i++)
30 {
31 if (pattern[i] != '?' && sig[i] != ptr[i])
32 {
33 found = false;
34 break;
35 }
36 }
37
38 if (found)
39 return ptr;
40
41 ptr++;
42 }
43
44 return NULL;
45}
46
47bool CModuleScanner::GetLibraryInfo(const void *libPtr, DynLibInfo &lib)
48{
49 unsigned long baseAddr;
50 Dl_info info;
51 Elf32_Ehdr *file;
52 Elf32_Phdr *phdr;
53 uint16_t phdrCount;
54
55 if (libPtr == NULL)
56 return false;
57
58 if (!dladdr(libPtr, &info))
59 return false;
60
61 if (!info.dli_fbase || !info.dli_fname)
62 return false;
63
64 /* This is for our insane sanity checks :o */
65 baseAddr = reinterpret_cast<unsigned long>(info.dli_fbase);
66 file = reinterpret_cast<Elf32_Ehdr *>(baseAddr);
67
68 /* Check ELF magic */
69 if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0)
70 return false;
71
72 /* Check ELF version */
73 if (file->e_ident[EI_VERSION] != EV_CURRENT)
74 return false;
75
76 /* Check ELF architecture, which is 32-bit/x86 right now
77 * Should change this for 64-bit if Valve gets their act together
78 */
79 if (file->e_ident[EI_CLASS] != ELFCLASS32 || file->e_machine != EM_386 || file->e_ident[EI_DATA] != ELFDATA2LSB)
80 return false;
81
82 /* For our purposes, this must be a dynamic library/shared object */
83 if (file->e_type != ET_DYN)
84 return false;
85
86 phdrCount = file->e_phnum;
87 phdr = reinterpret_cast<Elf32_Phdr *>(baseAddr + file->e_phoff);
88
89 /* Add up the memory sizes of segments marked as PT_LOAD as those are the only ones that should be in memory */
90 for (uint16_t i = 0; i < phdrCount; i++)
91 {
92 Elf32_Phdr &hdr = phdr[i];
93 if (hdr.p_type == PT_LOAD)
94 lib.memorySize += hdr.p_memsz;
95 }
96
97 lib.baseAddress = reinterpret_cast<void *>(baseAddr);
98 return true;
99}
diff --git a/ModuleScanner.h b/ModuleScanner.h
new file mode 100644
index 0000000..7fe2fdb
--- /dev/null
+++ b/ModuleScanner.h
@@ -0,0 +1,18 @@
1#include <stdlib.h>
2
3struct DynLibInfo
4{
5 void *baseAddress;
6 size_t memorySize;
7};
8
9class CModuleScanner
10{
11 public:
12 CModuleScanner(void *addr);
13 void *FindSignature(const char *sig, const char *pattern);
14
15 private:
16 bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib);
17 void *m_addr;
18};
diff --git a/sigscan.cpp b/sigscan.cpp
new file mode 100644
index 0000000..f8ab0e3
--- /dev/null
+++ b/sigscan.cpp
@@ -0,0 +1,124 @@
1#include <string.h>
2#include "sigscan.h"
3
4/* There is no ANSI ustrncpy */
5unsigned char* ustrncpy(unsigned char *dest, const unsigned char *src, int len) {
6 while(len--)
7 dest[len] = src[len];
8
9 return dest;
10}
11
12/* //////////////////////////////////////
13 CSigScan Class
14 ////////////////////////////////////// */
15unsigned char* CSigScan::base_addr;
16size_t CSigScan::base_len;
17void *(*CSigScan::sigscan_dllfunc)(const char *pName, int *pReturnCode);
18
19/* Initialize the Signature Object */
20int CSigScan::Init(const unsigned char *sig, const char *mask, size_t len) {
21 is_set = 0;
22
23 sig_len = len;
24
25 if ( sig_str )
26 delete[] sig_str;
27
28 sig_str = new unsigned char[sig_len];
29 ustrncpy(sig_str, sig, sig_len);
30
31 if ( sig_mask )
32 delete[] sig_mask;
33
34 sig_mask = new char[sig_len/*+1*/];
35 strncpy(sig_mask, mask, sig_len);
36 //sig_mask[sig_len+1] = 0;
37
38 if(!base_addr)
39 return 2; // GetDllMemInfo() Failed
40
41 if((sig_addr = FindSignature()) == NULL)
42 return 1; // FindSignature() Failed
43
44 is_set = 1;
45 // SigScan Successful!
46
47 return 0;
48}
49
50/* Destructor frees sig-string allocated memory */
51CSigScan::~CSigScan(void) {
52 delete[] sig_str;
53 delete[] sig_mask;
54}
55
56/* Get base address of the server module (base_addr) and get its ending offset (base_len) */
57bool CSigScan::GetDllMemInfo(void) {
58 void *pAddr = (void*)sigscan_dllfunc;
59 base_addr = 0;
60 base_len = 0;
61
62 #ifdef WIN32
63 MEMORY_BASIC_INFORMATION mem;
64
65 if(!pAddr)
66 return false; // GetDllMemInfo failed!pAddr
67
68 if(!VirtualQuery(pAddr, &mem, sizeof(mem)))
69 return false;
70
71 base_addr = (unsigned char*)mem.AllocationBase;
72
73 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER*)mem.AllocationBase;
74 IMAGE_NT_HEADERS *pe = (IMAGE_NT_HEADERS*)((unsigned long)dos+(unsigned long)dos->e_lfanew);
75
76 if(pe->Signature != IMAGE_NT_SIGNATURE) {
77 base_addr = 0;
78 return false; // GetDllMemInfo failedpe points to a bad location
79 }
80
81 base_len = (size_t)pe->OptionalHeader.SizeOfImage;
82
83 #else
84
85 Dl_info info;
86 struct stat buf;
87
88 if(!dladdr(pAddr, &info))
89 return false;
90
91 if(!info.dli_fbase || !info.dli_fname)
92 return false;
93
94 if(stat(info.dli_fname, &buf) != 0)
95 return false;
96
97 base_addr = (unsigned char*)info.dli_fbase;
98 base_len = buf.st_size;
99 #endif
100
101 return true;
102}
103
104/* Scan for the signature in memory then return the starting position's address */
105void* CSigScan::FindSignature(void) {
106 unsigned char *pBasePtr = base_addr;
107 unsigned char *pEndPtr = base_addr+base_len;
108 size_t i;
109
110 while(pBasePtr < pEndPtr) {
111 for(i = 0;i < sig_len;i++) {
112 if((sig_mask[i] != '?') && (sig_str[i] != pBasePtr[i]))
113 break;
114 }
115
116 // If 'i' reached the end, we know we have a match!
117 if(i == sig_len)
118 return (void*)pBasePtr;
119
120 pBasePtr++;
121 }
122
123 return NULL;
124}
diff --git a/sigscan.h b/sigscan.h
new file mode 100644
index 0000000..f6727a9
--- /dev/null
+++ b/sigscan.h
@@ -0,0 +1,64 @@
1#ifndef SIGSCAN_H
2#define SIGSCAN_H
3
4#include <stdio.h>
5
6#ifdef _WIN32
7 #define WIN32_LEAN_AND_MEAN
8 #include <windows.h>
9#else
10 #include <dlfcn.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13#endif
14
15class CSigScan {
16private:
17 /* Private Variables */
18 /* Base Address of the server module in memory */
19 static unsigned char *base_addr;
20 /* The length to the module's ending address */
21 static size_t base_len;
22
23 /* The signature to scan for */
24 unsigned char *sig_str;
25 /* A mask to ignore certain bytes in the signature such as addresses
26 The mask should be as long as all the bytes in the signature string
27 Use '?' to ignore a byte and 'x' to check it
28 Example: "xxx????xx" - The first 3 bytes are checked, then the next 4 are
29 ignored, then the last 2 are checked */
30 char *sig_mask;
31 /* The length of sig_str and sig_mask (not including a terminating null for sig_mask) */
32 size_t sig_len;
33
34 /* Private Functions */
35 void* FindSignature(void);
36
37public:
38 /* Public Variables */
39
40 /* sigscan_dllfunc is a pointer of something that resides inside the gamedll so we can get
41 the base address of it. From a SourceMM plugin, just set this to ismm->serverFactory(0)
42 in Load(). From a Valve Server Plugin, you must set this to an actual factory returned
43 from gameServerFactory and hope that a SourceMM plugin did not override it. */
44 static void *(*sigscan_dllfunc)(const char *pName, int *pReturnCode);
45
46 /* If the scan was successful or not */
47 char is_set;
48 /* Starting address of the found function */
49 void *sig_addr;
50
51 CSigScan(void): sig_str(NULL), sig_mask(NULL), sig_len(0), sig_addr(NULL) {}
52 ~CSigScan(void);
53
54 static bool GetDllMemInfo(void);
55 int Init(const unsigned char *sig, const char *mask, size_t len);
56};
57
58/* Sigscanned member functions are casted to member function pointers of this class
59 and called with member function pointer syntax */
60class EmptyClass { };
61
62void InitSigs(void);
63
64#endif