(Choose “multibyte character set” for all program: proj property>general>character set.)
scan/sniff System vulnerability (buffer overflow, openssl heartbleed, …)
=> break-in
=> malware installation (virus, backdoor, rootkit, ransomware, …)
=> system control (dll injection, api hooking, …)
target.cpp
:
#include <windows.h>
#include <stdio.h>
int main(){
printf("hello from target\n");
for(;;);
}
access project:
#include "windows.h"
#include "psapi.h"
#include "stdio.h"
int main(){
// get handle of the victim process. assume 3436 is the PID of the target.exe
// find pid of target.exe with Taskmanager.
HANDLE hProcess=
OpenProcess(PROCESS_ALL_ACCESS,FALSE,3436);
// and display some information about the victim
DWORD res=GetPriorityClass(hProcess); // priority class of the victim
printf("priority:%x\n", res);
// also display the name of the program name
char buf[MAX_PATH];
GetModuleFileNameEx(hProcess, 0, buf, MAX_PATH);
printf("program name:%s\n", buf);
}
#include <windows.h>
#include <stdio.h>
int main(){
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb=sizeof(si);
ZeroMemory(&pi, sizeof(pi));
char *fname="G:\\kim\\LectureNotes\\security\\2017\\malware\\target\\Debug\\target.exe";
if (!CreateProcess(NULL, fname, NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)){ // create a child
printf("createprocess failed:%d\n", GetLastError());
return 0;
}
// now pi.hProcess is the handle to the new process, pi.dwProcessId is the pid
printf("child pid:%d\n", pi.dwProcessId); // show child's pid
WaitForSingleObject(pi.hProcess, INFINITE); // wait until child is done
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
The above program should run target.exe
.
We can load DLL into current process.
test.dll
(win32 console> project name “test” > next>check “DLL”, uncheck all extra option and check “empty proj”)
(Also for later version of visual studio, overwrite dllmain.cpp with the code below and disable precompiled header (c/c++>precompiled header>No))
#include "windows.h"
#include "stdio.h"
void foo(int x){
printf("you called foo with %d\n", x);
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason,LPVOID lpvReserved){
switch(fdwReason){
case DLL_PROCESS_ATTACH:
MessageBox(NULL,"test","test",NULL);
foo(30);
break;
}
return TRUE;
}
When you compile above, you should have test.dll in test/Debug folder. Remember you can not run DLL file; you can only load it into another program.
loadDll project
#include "windows.h"
int main(){
LoadLibrary("G:\\kim\\LectureNotes\\security\\2017\\malware\\test\\Debug\\test.dll");
}
The above program should load “test.dll”. When a dll is loaded, the system automatically runs its “DllMain()” which, in this case, displays a message box. Sometimes the security program in your system may delete “loadDll.exe” thinking it is dangerous. Check if you have loadDll.exe after compiling. If not, you should block the security program for a while.
findFunc1 project:
#include "windows.h"
#include "stdio.h"
int main(){
HMODULE hMod=GetModuleHandle("kernel32.dll");
LPTHREAD_START_ROUTINE pThreadProc=
(LPTHREAD_START_ROUTINE)GetProcAddress(hMod,"LoadLibraryA");
printf("findFunc1 LoadLibrary at:%p\n", pThreadProc);
}
findFunc2 project:
#include "windows.h"
#include "stdio.h"
int main(){
HMODULE hMod=GetModuleHandle("kernel32.dll");
LPTHREAD_START_ROUTINE pThreadProc=
(LPTHREAD_START_ROUTINE)GetProcAddress(hMod,"LoadLibraryA");
printf("findFunc2 LoadLibrary at:%p\n", pThreadProc);
}
#include "windows.h"
#include "stdio.h"
int main() {
LPCTSTR szDllName = "remote hello";
// get handle of target process
HANDLE hProcess =
OpenProcess(PROCESS_ALL_ACCESS, FALSE, 3436); // 3436 is target.exe pid
// get handle of current process for comparison
HANDLE hProcessCurr =
OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); // cur proc pid
// alloc mem in target's addr space
DWORD dwBufSize = 20;
LPVOID pRemoteBuf =
VirtualAllocEx(hProcess, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
// also alloc mem in current process's addr space for comparison
LPVOID pRemoteBufCurr =
VirtualAllocEx(hProcessCurr, NULL, dwBufSize, MEM_COMMIT, PAGE_READWRITE);
// write "remote hello" into remote memory
WriteProcessMemory(hProcess, pRemoteBuf, (LPVOID)szDllName, dwBufSize, NULL);
// also write it into curr space for comparison
WriteProcessMemory(hProcessCurr, pRemoteBufCurr, (LPVOID)szDllName, dwBufSize, NULL);
// pRemoteBuf is the address in the remote process
printf("buf addr:%p\n", pRemoteBuf);
// pRemoteBufCurr is the address in the current process
printf("bufcurr addr:%p\n", pRemoteBufCurr);
printf("bufcurr:%s\n", pRemoteBufCurr); // we can display string in curr space
//printf("buf:%s\n", pRemoteBuf); // (1). but we can't display remote string
CloseHandle(hProcess);
CloseHandle(hProcessCurr);
}
injectDLL project:
#include "windows.h"
int main(){
LPCTSTR szDllName= // attack dll path
"D:\\kim\\LectureNotes\\security\\2019\\malware\\test\\Debug\\test.dll";
// step 1. get handle of victim process
HANDLE hProcess=
OpenProcess(PROCESS_ALL_ACCESS,FALSE,1234); // 1234 is victim's pid
// step 2. alloc mem in target's addr space to store attack dll path to injection code
DWORD dwBufSize=lstrlen(szDllName)+1;
LPVOID pRemoteBuf=
VirtualAllocEx(hProcess,NULL,dwBufSize,MEM_COMMIT,PAGE_READWRITE);
// step 3. write "test.dll" path into alloc'd mem
WriteProcessMemory(hProcess,pRemoteBuf,(LPVOID)szDllName,dwBufSize,NULL);
// step 4. get LoadLibraryA addr which is in kernel32.dll.
// GetModuleHandle returns the handle of a DLL ("kernel32.dll")
// GetProcAddress will return address of a function ("LoadLibraryA") in a DLL ("kernel32.dll")
HMODULE hMod=GetModuleHandle("kernel32.dll");
LPTHREAD_START_ROUTINE pThreadProc=
(LPTHREAD_START_ROUTINE)GetProcAddress(hMod,"LoadLibraryA");
// step 5. run remote thread
// CreateRemoteThread will make a thread in the victim process ("hProcess").
// The thread starting location is pThreadProc, and its parameter in pRemoteBuf.
// This thread will run LoadLibraryA in the victim process which in turn will load testdll.dll
// and run it.
HANDLE hThread=
CreateRemoteThread(hProcess,NULL,0,pThreadProc,pRemoteBuf,0,NULL);
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
return TRUE;
}
The above program will inject “test.dll” into “victim.exe”. You should see a message box displayed by “test.dll”.
injectDLL2:
#include <windows.h>
#include "stdio.h"
int main(){
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb=sizeof(si);
ZeroMemory(&pi, sizeof(pi));
char * fname=
"D:\\kim\\LectureNotes\\security\\2019\\malware\\target\\Debug\\target.exe";
if (!CreateProcess(NULL, fname, NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)){
printf("createprocess failed:%d\n", GetLastError());
return 0;
}
// now pi.hProcess is the handle to the new process, pi.dwProcessId is the pid
printf("child pid:%d\n", pi.dwProcessId); // show child's pid
LPCTSTR szDllName=
"D:\\kim\\LectureNotes\\security\\2019\\malware\\test\\Debug\\test.dll";
// step 1. get handle of victim process
HANDLE hProcess=pi.hProcess;
// step 2. alloc mem in target's addr space by size of dwBufSize
DWORD dwBufSize=lstrlen(szDllName)+1;
LPVOID pRemoteBuf=
VirtualAllocEx(hProcess,NULL,dwBufSize,MEM_COMMIT,PAGE_READWRITE);
// step 3. write "dlltest.dll" path into alloc'd mem
WriteProcessMemory(hProcess,pRemoteBuf,(LPVOID)szDllName,dwBufSize,NULL);
// step 4. get LoadLibraryA addr
HMODULE hMod=GetModuleHandle("kernel32.dll");
LPTHREAD_START_ROUTINE pThreadProc=
(LPTHREAD_START_ROUTINE)GetProcAddress(hMod,"LoadLibraryA");
// step 5. run thread
HANDLE hThread=
CreateRemoteThread(hProcess,NULL,0,pThreadProc,pRemoteBuf,0,NULL);
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
CloseHandle(pi.hThread);
return TRUE;
}
The above program will run “target.exe” and inject “test.dll” into “target.exe”.
victim2:(Before running this, you should make “f1.txt” in victim2/Debug directory)
#include "windows.h"
int main(){
MessageBox(NULL,"hello from victim2","test",NULL);
CopyFileW(
L"G:\\kim\\LectureNotes\\security\\2017\\malware\\victim2\\Debug\\f1.txt",
L"G:\\kim\\LectureNotes\\security\\2017\\malware\\victim2\\Debug\\f2.txt",
FALSE);
}
injectDLL3:
#include <windows.h>
#include "stdio.h"
int main(){
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb=sizeof(si);
ZeroMemory(&pi, sizeof(pi));
char * fname=
"G:\\kim\\LectureNotes\\security\\2017\\malware\\victim2\\Debug\\victim2.exe";
if (!CreateProcess(NULL, fname, NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)){
printf("createprocess failed:%d\n", GetLastError());
return 0;
}
// now pi.hProcess is the handle to the new process, pi.dwProcessId is the pid
printf("child pid:%d\n", pi.dwProcessId); // show child's pid
LPCTSTR szDllName=
"G:\\kim\\LectureNotes\\security\\2017\\malware\\sharedModule\\Debug\\sharedModule.dll";
// step 1. get handle of victim process
HANDLE hProcess=pi.hProcess;
// step 2. alloc mem in target's addr space by size of dwBufSize
DWORD dwBufSize=lstrlen(szDllName)+1;
LPVOID pRemoteBuf=
VirtualAllocEx(hProcess,NULL,dwBufSize,MEM_COMMIT,PAGE_READWRITE);
// step 3. write "test.dll" path into alloc'd mem
WriteProcessMemory(hProcess,pRemoteBuf,(LPVOID)szDllName,dwBufSize,NULL);
// step 4. get LoadLibraryA addr
HMODULE hMod=GetModuleHandle("kernel32.dll");
LPTHREAD_START_ROUTINE pThreadProc=
(LPTHREAD_START_ROUTINE)GetProcAddress(hMod,"LoadLibraryA");
// step 5. run thread
HANDLE hThread=
CreateRemoteThread(hProcess,NULL,0,pThreadProc,pRemoteBuf,0,NULL);
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
CloseHandle(hProcess);
CloseHandle(pi.hThread);
return TRUE;
}
sharedModule.dll
(When compiling this, you need to add “imagehlp.lib” in the linker.)
(Also for later version of visual studio, overwrite dllmain.cpp with the code below and disable precompiled header (c/c++>precompiled header>No))
(original code is at: https://www.codeproject.com/Articles/4118/API-Monitoring-Unleashed)
#include "windows.h"
#include <stdio.h>
#include <imagehlp.h>
#include <stdlib.h>
HANDLE g_hModule = INVALID_HANDLE_VALUE;
PROC g_OriginalCopyFileW;
typedef BOOL WINAPI MyCopyFileW_t
(
LPCWSTR lpExistingFileName,
LPCWSTR lpNewFileName,
BOOL bFailIfExists
);
BOOL WINAPI MyCopyFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists)
{
BOOL ReturnValue;
MyCopyFileW_t* fn = (MyCopyFileW_t*)g_OriginalCopyFileW;
ReturnValue = (*fn)(lpExistingFileName, lpNewFileName, bFailIfExists);
return ReturnValue;
}
void SetHook(HMODULE hModuleOfCaller, LPSTR LibraryName, PROC OldFunctionPointer, PROC NewFunctionPointer)
{
if(hModuleOfCaller == g_hModule)
return;
if(hModuleOfCaller == 0)
return;
ULONG ulSize;
// Get the address of the module's import section
PIMAGE_IMPORT_DESCRIPTOR pImportDesc =
(PIMAGE_IMPORT_DESCRIPTOR) ImageDirectoryEntryToData(
hModuleOfCaller,
TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&ulSize);
// Does this module have an import section ?
if (pImportDesc == NULL)
return;
// Loop through all descriptors and find the
// import descriptor containing references to callee's functions
while (pImportDesc->Name)
{
PSTR pszModName = (PSTR)((PBYTE) hModuleOfCaller + pImportDesc->Name);
if (stricmp(pszModName, LibraryName) == 0)
break; // Found
pImportDesc++;
} // while
if (pImportDesc->Name == 0)
return;
//Get caller's IAT
PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)( (PBYTE) hModuleOfCaller + pImportDesc->FirstThunk );
PROC pfnCurrent = OldFunctionPointer;
// Replace current function address with new one
while (pThunk->u1.Function)
{
// Get the address of the function address
PROC* ppfn = (PROC*) &pThunk->u1.Function;
// Is this the function we are looking for?
BOOL bFound = (*ppfn == pfnCurrent);
if (bFound)
{
MEMORY_BASIC_INFORMATION mbi;
::VirtualQuery(ppfn, &mbi, sizeof(MEMORY_BASIC_INFORMATION));
// In order to provide writable access to this part of the
// memory we need to change the memory protection
if (FALSE == ::VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_READWRITE,&mbi.Protect))
return;
*ppfn = *NewFunctionPointer;
BOOL bResult = TRUE;
// Restore the protection back
DWORD dwOldProtect;
::VirtualProtect(mbi.BaseAddress,mbi.RegionSize,mbi.Protect,&dwOldProtect);
break;
} // if
pThunk++;
} // while
}
PROC EnumAndSetHooks(LPSTR BaseLibraryName, LPSTR BaseFunctionName, PROC NewFunctionPointer, bool UnHook, PROC Custom)
{
HMODULE hMods[1024];
DWORD cbNeeded;
unsigned int i;
typedef BOOL (WINAPI * PFNENUMPROCESSMODULES)
(
HANDLE hProcess,
HMODULE *lphModule,
DWORD cb,
LPDWORD lpcbNeeded
);
HMODULE hBaseLib = LoadLibrary(BaseLibraryName);
PROC hBaseProc;
if(UnHook)
hBaseProc = (PROC) Custom;
else
hBaseProc = GetProcAddress(hBaseLib, BaseFunctionName);
PFNENUMPROCESSMODULES m_pfnEnumProcessModules;
HMODULE m_hModPSAPI = ::LoadLibraryA("PSAPI.DLL");
m_pfnEnumProcessModules = (PFNENUMPROCESSMODULES)::GetProcAddress(m_hModPSAPI, "EnumProcessModules");
HANDLE hProcess = ::GetCurrentProcess();
if( m_pfnEnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
{
SetHook(hMods[i], BaseLibraryName, hBaseProc, NewFunctionPointer);
}
}
return hBaseProc;
}
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_hModule = hModule;
g_OriginalCopyFileW = EnumAndSetHooks("KERNEL32.DLL", "CopyFileW", (PROC) MyCopyFileW, false, 0);
break;
case DLL_PROCESS_DETACH:
EnumAndSetHooks("KERNEL32.DLL", "CopyFileW", (PROC) GetProcAddress(LoadLibrary("KERNEL32"),"CopyFileW"), true, (PROC) MyCopyFileW);
break;
}
return TRUE;
}
In the above code, attack3 injects sharedModule.dll into victim2. At this point we have three threads: attack3, victim2, and sharaedModule.dll. attack3 is waiting on “WaitForSingleObject”, victim2 runs first, display, “hello from victim2” and is waiting on user clicking on “Confirm” button. sharedModule.dll runs next and changes CopyFileW to MyCopyFileW. When the user clicks on “Confirm” button, victim2 runs “CopyFileW” which is changed to “MyCopyFileW” which will copy f1.txt to f2.txt (you should see f2.txt created in victim2/Debug).
sharedModule:
..............
BOOL WINAPI MyCopyFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists)
{
BOOL ReturnValue;
MessageBox(NULL,"hooked copy file",NULL,NULL);
MyCopyFileW_t* fn = (MyCopyFileW_t*)g_OriginalCopyFileW;
ReturnValue = (*fn)(lpExistingFileName, lpNewFileName, bFailIfExists);
return ReturnValue;
}
..................
In the above code, attack3 injects sharedModule.dll into victim2. At this point we have three threads: attack3, victim2, and sharaedModule.dll. attack3 is waiting on “WaitForSingleObject”, victim2 runs first, display, “hello from victim2” and is waiting on user clicking on “Confirm” button. sharedModule.dll runs next and changes CopyFileW to MyCopyFileW. When the user clicks on “Confirm” button, victim2 runs “CopyFileW” which is changed to “MyCopyFileW” which in turn displays “hooked copy file” and performs actual file copying.
Try the code in 4.1-4.14 above and explain the results.