00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "CATDLLInjector.h"
00014 #include "CATStreamFile.h"
00015
00016
00017 #ifdef CAT_CONFIG_WIN32
00018 #include <psapi.h>
00019
00020
00021 CATResult CATDLLInjector::InjectIntoProcess(const CATWChar* dllPath,
00022 CATUInt32 pid)
00023 {
00024
00025 CATWChar dllFile[_MAX_PATH+1];
00026 LPWSTR* filePart = 0;
00027 if (0 == ::GetFullPathName(dllPath,_MAX_PATH+1,dllFile,filePart))
00028 {
00029 return CAT_ERR_FILE_NOT_FOUND;
00030 }
00031
00032 HMODULE testLoad = 0;
00033 if (0 == (testLoad = LoadLibraryEx(dllFile, 0, LOAD_LIBRARY_AS_DATAFILE)))
00034 {
00035 return CAT_ERR_FILE_NOT_FOUND;
00036 }
00037 FreeLibrary(testLoad);
00038
00039
00040 HANDLE hToken;
00041 TOKEN_PRIVILEGES tkp;
00042 if (OpenProcessToken(GetCurrentProcess(),
00043 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
00044 &hToken))
00045 {
00046 LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid);
00047 tkp.PrivilegeCount = 1;
00048 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
00049 AdjustTokenPrivileges(hToken,
00050 FALSE,
00051 &tkp,
00052 0,
00053 (PTOKEN_PRIVILEGES) NULL,
00054 0);
00055 CloseHandle(hToken);
00056 }
00057
00058
00059 HANDLE proc = ::OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
00060 if (NULL == proc)
00061 {
00062 return CAT_ERR_UNABLE_TO_OPEN_PROCESS;
00063 }
00064
00065
00066 SIZE_T dllNameLen = (wcslen(dllFile)+1)*sizeof(CATWChar);
00067
00068 LPVOID procMem = ::VirtualAllocEx(proc,
00069 0,
00070 dllNameLen,
00071 MEM_RESERVE|MEM_COMMIT,
00072 PAGE_READWRITE);
00073 if (!procMem)
00074 {
00075 CloseHandle(proc);
00076 return CAT_ERR_REMOTE_ALLOC_RAM;
00077 }
00078
00079
00080 SIZE_T amountWritten = 0;
00081 if (!WriteProcessMemory(proc,procMem,dllFile,dllNameLen,&amountWritten))
00082 {
00083 CloseHandle(proc);
00084 return CAT_ERR_REMOTE_WRITE;
00085 }
00086
00087
00088 FARPROC loadLibFunc = ::GetProcAddress(
00089 ::GetModuleHandle(L"kernel32.dll"),
00090 "LoadLibraryW");
00091
00092
00093
00094 DWORD threadId = 0;
00095 HANDLE remoteThread = ::CreateRemoteThread(
00096 proc,
00097 0,
00098 0,
00099 (LPTHREAD_START_ROUTINE)loadLibFunc,
00100 procMem,
00101 0,
00102 &threadId);
00103
00104 if (remoteThread == 0)
00105 {
00106 CloseHandle(proc);
00107 return CAT_ERR_REMOTE_CREATE_THREAD;
00108 }
00109
00110
00111 DWORD waitResult;
00112 waitResult = WaitForSingleObject(remoteThread,30000);
00113
00114 if (waitResult != WAIT_OBJECT_0)
00115 {
00116 CloseHandle(proc);
00117 CloseHandle(remoteThread);
00118 return CAT_ERR_REMOTE_THREAD_TIMEOUT;
00119 }
00120
00121
00122 CATResult result = 0;
00123 DWORD exitCode = 0;
00124
00125 ::GetExitCodeThread(remoteThread,&exitCode);
00126 if (exitCode == 0)
00127 {
00128 result = CAT_ERR_REMOTE_THREAD_INVALID_EXIT;
00129 }
00130 else
00131 {
00132 result = (CATResult)exitCode;
00133 }
00134
00135
00136 CloseHandle(remoteThread);
00137 ::VirtualFreeEx(proc,procMem,wcslen(dllFile)*sizeof(CATWChar),MEM_RELEASE);
00138 CloseHandle(proc);
00139
00140 return exitCode;
00141 }
00142
00143 CATResult CATDLLInjector::GetProcessId(const CATWChar *processName,
00144 CATUInt32& pid,
00145 CATUInt32 procIndex)
00146 {
00147 CATASSERT(processName != 0, "Invalid process name passed to GetProcessId()");
00148 if (processName == 0)
00149 return CATRESULT(CAT_ERR_INVALID_PARAM);
00150
00151 DWORD procIdArray[1024];
00152 DWORD lengthNeeded = 0;
00153 CATUInt32 numFound = 0;
00154 CATResult result = CAT_SUCCESS;
00155
00156 pid = 0;
00157
00158
00159
00160 if ( !EnumProcesses( procIdArray,
00161 sizeof(procIdArray),
00162 &lengthNeeded ) )
00163 {
00164 return CATRESULT(CAT_ERR_ENUM_PROCS);
00165 }
00166
00167 DWORD numProcs = lengthNeeded / sizeof(DWORD);
00168
00169 CATWChar testName[_MAX_PATH+1];
00170
00171 CATUInt32 curProcIndex = 0;
00172
00173
00174
00175 for ( DWORD i = 0; i < numProcs; i++ )
00176 {
00177 HANDLE procHandle = OpenProcess( PROCESS_QUERY_INFORMATION |
00178 PROCESS_VM_READ,
00179 FALSE, procIdArray[i] );
00180
00181 if (NULL != procHandle )
00182 {
00183 HMODULE module = 0;
00184 DWORD lengthNeeded = 0;
00185
00186 if ( EnumProcessModules( procHandle,
00187 &module,
00188 sizeof(module),
00189 &lengthNeeded) )
00190 {
00191 memset(testName,0,sizeof(testName));
00192 GetModuleBaseName( procHandle,
00193 module,
00194 testName,
00195 sizeof(testName) );
00196
00197 if (0 == _wcsicmp(testName, processName))
00198 {
00199
00200
00201 if ((procIndex == -1) || (curProcIndex == procIndex))
00202 {
00203 pid = procIdArray[i];
00204 }
00205 curProcIndex++;
00206 numFound++;
00207 }
00208 }
00209 else
00210 {
00211 CloseHandle(procHandle);
00212 }
00213 }
00214 else
00215 {
00216 continue;
00217 }
00218 }
00219
00220 if (numFound == 0)
00221 {
00222 return CATRESULT(CAT_ERR_NO_MATCHING_PROC);
00223 }
00224 else if (numFound == 1)
00225 {
00226 return CAT_SUCCESS;
00227 }
00228
00229 return CATRESULT(CAT_STAT_MULTIPLE_PROCS);
00230 }
00231
00232
00233
00234
00235
00236
00237
00238 const CATUInt8 kAsmPatch[] =
00239 {
00240
00241
00242
00243
00244
00245 0x90,
00246 0x68,
00247 0x00,0x00,0x00,0x00,
00248
00249 0x60,0x9c,
00250 0x90,0x90,0x90,
00251
00252
00253 0x68,
00254 0x00,0x00,0x00,0x00,
00255
00256
00257
00258 0xff,0x15,
00259 0x00,0x00,0x00,0x00,
00260
00261
00262
00263
00264 0x68,
00265 0x00,0x00,0x00,0x00,
00266
00267 0x50,
00268
00269 0xff,0x15,
00270 0x00,0x00,0x00,0x00,
00271
00272
00273
00274
00275 0x68,
00276 0x00,0x00,0x00,0x00,
00277 0x68,
00278 0x00,0x00,0x00,0x00,
00279 0x68,
00280 0x00,0x00,0x00,0x00,
00281 0x68,
00282 0x00,0x00,0x00,0x00,
00283 0x68,
00284 0x00,0x00,0x00,0x00,
00285 0x68,
00286 0x00,0x00,0x00,0x00,
00287
00288 0xff,0xd0,
00289 0xcc,0x90,
00290
00291 0x00,0x00,0x00,0x00,
00292 0x00,0x00,0x00,0x00,
00293
00294 0x55,0x6E,0x70,0x61,0x74,
00295 0x63,0x68,0x50,0x72,0x6F,
00296 0x63,0x65,0x73,0x73,0x00
00297 };
00298
00299
00300 const int kStartLocReturn = 2;
00301 const int kDLLNameOffAddr = 12;
00302 const int kLoadLibraryOffset = 18;
00303 const int kUnpatchFuncOffset = 23;
00304 const int kGetProcAddressOffset = 30;
00305 const int kHostProcOffset = 35;
00306 const int kHostBufferOffset = 40;
00307 const int kPatchSizeOffset = 45;
00308 const int kStartLocOffset = 50;
00309 const int kPassDataLenOffset = 55;
00310 const int kPassDataOffset = 60;
00311 const int kLoadLibraryAddress = 68;
00312 const int kGetProcAddress = 72;
00313 const int kUnpatchFuncNameAddress= 76;
00314 const int kDLLNameOffset = sizeof(kAsmPatch);
00315
00316
00317
00318 CATResult CATDLLInjector::StartDLLWithProcess (const CATWChar* dllPath,
00319 const CATWChar* execFile,
00320 const CATWChar* commandLine,
00321 const void* passData,
00322 CATUInt32 passDataLen)
00323 {
00324
00325 HANDLE hToken;
00326 TOKEN_PRIVILEGES tkp;
00327 if (OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
00328 {
00329 LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tkp.Privileges[0].Luid);
00330 tkp.PrivilegeCount = 1;
00331 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
00332 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
00333 CloseHandle(hToken);
00334 }
00335
00336 CATResult result;
00337
00338
00339 CATWChar targDir[_MAX_PATH+1];
00340 wcscpy(targDir,execFile);
00341 CATWChar* slash = wcsrchr(targDir,'\\');
00342 if (slash != 0)
00343 {
00344 *slash = 0;
00345 }
00346
00347
00348
00349 CATWChar dllFile[_MAX_PATH+1];
00350 LPWSTR filePart = 0;
00351 if (0 == ::GetFullPathName(dllPath,_MAX_PATH+1,dllFile,&filePart))
00352 {
00353 return CATRESULTFILE(CAT_ERR_FILE_NOT_FOUND,dllPath);
00354 }
00355
00356 HMODULE testLoad = 0;
00357 if (0 == (testLoad = LoadLibraryEx(dllFile, 0, LOAD_LIBRARY_AS_DATAFILE)))
00358 {
00359 return CATRESULTFILE(CAT_ERR_FILE_NOT_FOUND,dllFile);
00360 }
00361 FreeLibrary(testLoad);
00362
00363
00364
00365 CATStreamFile targetFile;
00366 if (CATFAILED(result = targetFile.Open(execFile,CATStream::READ_ONLY)))
00367 {
00368 return result;
00369 }
00370
00371
00372
00373 CATUInt8 dosHeader[0x40];
00374 IMAGE_NT_HEADERS peHeader;
00375 CATUInt32 peHeaderOffset = 0;
00376 CATUInt32 amountRead = 0;
00377 void* startLoc = 0;
00378 CATUInt8* storedBytes = 0;
00379 SIZE_T storedLength = 0;
00380
00381
00382 amountRead = 0x40;
00383 result = targetFile.Read(dosHeader,amountRead);
00384
00385 if ((result == CAT_STAT_FILE_AT_EOF) || (CATFAILED(result)))
00386 {
00387 targetFile.Close();
00388 return CATRESULT(CAT_ERR_READING_TARGET_EXEC);
00389 }
00390
00391 if (dosHeader[0] == 'M' && dosHeader[1] == 'Z')
00392 {
00393
00394
00395 peHeaderOffset = *((long *)(&dosHeader[0x3c]));
00396
00397 if (peHeaderOffset == 0)
00398 {
00399
00400 targetFile.Close();
00401 return CAT_ERR_EXE_NOT_PE_FORMAT;
00402 }
00403
00404
00405 CATFileOffset peOffset;
00406 peOffset.dOffset.highOffset = 0;
00407 peOffset.dOffset.lowOffset = peHeaderOffset;
00408 if (CATFAILED(result = targetFile.SeekAbsolute(peOffset.qOffset)))
00409 {
00410 targetFile.Close();
00411 return result;
00412 }
00413
00414
00415 amountRead = sizeof(IMAGE_NT_HEADERS);
00416 if (CATFAILED(result = targetFile.Read(&peHeader,amountRead)) ||
00417 (amountRead != sizeof(IMAGE_NT_HEADERS)) )
00418 {
00419 targetFile.Close();
00420 return CATRESULT(CAT_ERR_READING_TARGET_EXEC);
00421 }
00422
00423 targetFile.Close();
00424
00425
00426 startLoc = (void *)(UINT_PTR)
00427 (peHeader.OptionalHeader.AddressOfEntryPoint +
00428 peHeader.OptionalHeader.ImageBase);
00429 }
00430 else
00431 {
00432 targetFile.Close();
00433 return CAT_ERR_EXE_NOT_PE_FORMAT;
00434 }
00435
00436
00437 PROCESS_INFORMATION procInfo;
00438 STARTUPINFO startupInfo;
00439
00440 memset(&procInfo,0,sizeof(PROCESS_INFORMATION));
00441 memset(&startupInfo,0,sizeof(STARTUPINFO));
00442
00443 startupInfo.cb = sizeof(STARTUPINFO);
00444
00445 if (!CreateProcess(execFile,
00446 (LPWSTR)commandLine,
00447 0,
00448 0,
00449 0,
00450 CREATE_SUSPENDED,
00451 0,
00452 targDir,
00453 &startupInfo,
00454 &procInfo))
00455 {
00456 return CAT_ERR_PROCESS_CREATE;
00457 }
00458
00459 if ((procInfo.hThread == INVALID_HANDLE_VALUE) ||
00460 (procInfo.hProcess == INVALID_HANDLE_VALUE))
00461 {
00462 return CAT_ERR_PROCESS_CREATE;
00463 }
00464
00465
00466 CATUInt32 patchSize = (CATUInt32)(sizeof(kAsmPatch) +
00467 (wcslen(dllFile)*2) + 2);
00468
00469
00470 DWORD oldProtect = 0;
00471 VirtualProtectEx( procInfo.hProcess,
00472 startLoc,
00473 patchSize,
00474 PAGE_EXECUTE_READWRITE,
00475 &oldProtect);
00476
00477
00478 storedBytes = new CATUInt8[patchSize];
00479
00480 SIZE_T memReadBytes = 0;
00481 ReadProcessMemory( procInfo.hProcess,
00482 startLoc,
00483 storedBytes,
00484 patchSize,
00485 &memReadBytes);
00486
00487 storedLength = memReadBytes;
00488
00489
00490 CATUInt8* writeBytes = new CATUInt8[patchSize];
00491
00492
00493 memcpy(writeBytes,kAsmPatch,sizeof(kAsmPatch));
00494
00495
00496 wcscpy( (CATWChar*)(writeBytes + sizeof(kAsmPatch)),dllFile);
00497
00498
00499 *((CATUInt32*)&writeBytes[kDLLNameOffAddr]) =
00500 (CATUInt32)(UINT_PTR)(((CATUInt8*)startLoc) + kDLLNameOffset);
00501
00502
00503 *((CATUInt32*)&writeBytes[kUnpatchFuncOffset]) =
00504 (CATUInt32)(UINT_PTR)(((CATUInt8*)startLoc) + kUnpatchFuncNameAddress);
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 HMODULE kernelHandle = GetModuleHandle(L"kernel32.dll");
00517 FARPROC loadLibFunc = GetProcAddress(kernelHandle,"LoadLibraryW");
00518 FARPROC getProcFunc = GetProcAddress(kernelHandle,"GetProcAddress");
00519
00520
00521
00522 *((CATUInt32*)&writeBytes[kLoadLibraryOffset]) =
00523 (CATUInt32)(UINT_PTR)(((CATUInt8*)startLoc) + kLoadLibraryAddress);
00524
00525
00526 *((CATUInt32*)&writeBytes[kGetProcAddressOffset]) =
00527 (CATUInt32)(UINT_PTR)(((CATUInt8*)startLoc) + kGetProcAddress);
00528
00529
00530 *((CATUInt32*)&writeBytes[kLoadLibraryAddress]) =
00531 (CATUInt32)(UINT_PTR)loadLibFunc;
00532
00533
00534 *((CATUInt32*)&writeBytes[kGetProcAddress]) =
00535 (CATUInt32)(UINT_PTR)getProcFunc;
00536
00537
00538
00539
00540
00541 *((CATUInt32*)&writeBytes[kHostProcOffset]) = (CATUInt32)_getpid();
00542 *((CATUInt32*)&writeBytes[kHostBufferOffset]) = (CATUInt32)(UINT_PTR)storedBytes;
00543 *((CATUInt32*)&writeBytes[kPatchSizeOffset]) = (CATUInt32)patchSize;
00544 *((CATUInt32*)&writeBytes[kStartLocOffset]) = (CATUInt32)(UINT_PTR)startLoc;
00545 *((CATUInt32*)&writeBytes[kPassDataOffset]) = (CATUInt32)(UINT_PTR)passData;
00546 *((CATUInt32*)&writeBytes[kPassDataLenOffset]) = passDataLen;
00547
00548
00549 *((CATUInt32*)&writeBytes[kStartLocReturn]) = (CATUInt32)(UINT_PTR)startLoc;
00550
00551
00552 memReadBytes = 0;
00553 WriteProcessMemory(procInfo.hProcess,
00554 startLoc,
00555 writeBytes,
00556 patchSize,
00557 &memReadBytes);
00558
00559
00560 delete [] writeBytes;
00561
00562
00563
00564 CATWChar eventName[64];
00565 wsprintf(eventName,L"UnpatchProcess_%d",_getpid());
00566 HANDLE unpatchEvent = ::CreateEvent(0,TRUE,FALSE,eventName);
00567
00568
00569 ResumeThread(procInfo.hThread);
00570
00571
00572
00573
00574 if (WAIT_TIMEOUT == WaitForSingleObject(unpatchEvent,60000))
00575 {
00576 delete [] storedBytes;
00577 CloseHandle(unpatchEvent);
00578 return CAT_ERR_UNPATCH_TIMEOUT;
00579 }
00580
00581
00582 VirtualProtectEx(procInfo.hProcess,
00583 startLoc,
00584 patchSize,
00585 oldProtect,
00586 &oldProtect);
00587
00588
00589 delete [] storedBytes;
00590 CloseHandle(procInfo.hThread);
00591 CloseHandle(procInfo.hProcess);
00592 CloseHandle(unpatchEvent);
00593
00594 return CAT_SUCCESS;
00595 }
00596
00597 #endif // CAT_CONFIG_WIN32