Hola buenas, hace pocos días estuve leyendo sobre el API hooking y de allí salté a la inyección de DLL, y más adelante pasé a la inyección de código, y ayudándome con un código que encontré en rohitab fuí dando forma a mi código y puse control de errores. Este es el link por si a alguien le interesa, me fue muy útil:
http://www.rohitab.com/discuss/topic/39357-code-cave-injection-tutorial-c/
El programa inyecta un MessageBox en la aplicación objetivo, tras salir el MessageBox y pulsar aceptar se cierra la aplicación objetivo. Desconozco el porqué, os dejo el código a ver si me podéis ayudar a saber:
#pragma once
#include <windows.h>
#include <shlobj.h>
#include <wininet.h>
#include <tlhelp32.h>
#include <shlwapi.h>
typedef int (WINAPI* MsgBoxParam)(HWND, LPCSTR, LPCSTR, UINT);
using namespace std;
struct PARAMETERS{
DWORD MessageBoxInj;
char text[50];
char caption[25];
int buttons;
//HWND handle;
};
DWORD GetPIDFromProcName(LPCWSTR procName);
DWORD MyFunc(PARAMETERS * myparam);
DWORD Useless();
bool Injecter();
DWORD GetPIDFromProcName(LPCWSTR procName)
{
PROCESSENTRY32 pe;
HANDLE thSnapShot;
BOOL retval;
thSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (thSnapShot == INVALID_HANDLE_VALUE)
{
return 0;
}
pe.dwSize = sizeof(PROCESSENTRY32);
retval = Process32First(thSnapShot, &pe);
while (retval)
{
if (!lstrcmp(pe.szExeFile, procName))
{
return pe.th32ProcessID;
}
retval = Process32Next(thSnapShot, &pe);
}
return 0;
}
static DWORD MyFunc(PARAMETERS * myparam){
MsgBoxParam MsgBox = (MsgBoxParam)myparam->MessageBoxInj;
int result = MsgBox(0, myparam->text, myparam->caption, myparam->buttons);
switch (result){
case IDOK:
//code
break;
case IDCANCEL:
//code
break;
}
return 0;
}
static DWORD useless(){
return 0;
}
//debe ser static para que el compilador las ponga juntas y calcule bien el tamaño :)
bool Injecter()
{
HANDLE proc = NULL;
DWORD pID = NULL;
if ((pID = GetPIDFromProcName(L"chrome.exe")) == NULL)// no GetTargetThreadIDFromProcName ^^
{
return false;
}
if ((proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pID)) == NULL)
{
return false;
}
char * mytext = "Hello by CodeCave!";
char * mycaption = "Injection result";
PARAMETERS data; //let's fill in a PARAMETERS struct
HINSTANCE hUserModule = LoadLibraryA("user32.dll");
if (hUserModule == NULL)
{
CloseHandle(proc);
return false;
}
data.MessageBoxInj = (DWORD)GetProcAddress(hUserModule, "MessageBoxA");
strcpy(data.text, mytext);
strcpy(data.caption, mycaption);
data.buttons = MB_OKCANCEL | MB_ICONQUESTION;
DWORD_PTR size_myFunc = (DWORD_PTR)((LPBYTE)useless - (LPBYTE)MyFunc);
LPVOID MyFuncAddress = NULL;
if ((MyFuncAddress = VirtualAllocEx(proc, NULL, size_myFunc, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == NULL)
{
CloseHandle(proc);
return false;
}
if (WriteProcessMemory(proc, MyFuncAddress, (LPVOID)MyFunc, size_myFunc, NULL) == NULL)
{
VirtualFree(MyFuncAddress, 0, MEM_RELEASE);
CloseHandle(proc);
return false;
}
LPVOID DataAddress = NULL;
if ((DataAddress = VirtualAllocEx(proc, NULL, sizeof(PARAMETERS), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)) == NULL)
{
CloseHandle(proc);
return false;
}
if (WriteProcessMemory(proc, DataAddress, (LPVOID)&data, sizeof(PARAMETERS), NULL) == NULL)
{
VirtualFree(MyFuncAddress, 0, MEM_RELEASE);
VirtualFree(DataAddress, 0, MEM_RELEASE);
CloseHandle(proc);
return false;
}
HANDLE thread = NULL;
if ((thread = CreateRemoteThread(proc, NULL, 0, (LPTHREAD_START_ROUTINE)MyFuncAddress, DataAddress, 0, NULL)) == NULL)
{
VirtualFree(MyFuncAddress, 0, MEM_RELEASE);
VirtualFree(DataAddress, 0, MEM_RELEASE);
CloseHandle(proc);
return false;
}
WaitForSingleObject(thread, INFINITE);
VirtualFree(MyFuncAddress, 0, MEM_RELEASE);
VirtualFree(DataAddress, 0, MEM_RELEASE);
CloseHandle(thread);
CloseHandle(proc);
cout << "Injection completed!" << endl;
return true;
}
Al ejecutar el programa ejecuta todo sin errore y muestra "Injection completed!", pero al cerrar el MessageBox que invoco el la aplicación a la que inyecto esta se me cierra también.
Creo que se debe al calculo del tamaño de la función a inyectar, quizás dependiendo de un compilador pueda variar el resultado.
Saludos y gracias.
¿GetTargetThreadIDFromProcName?
¿Podrías poner el código completo e indicar que compilador estas usando?
saludos.
Cita de: fary en 7 Abril 2016, 11:15 AM
¿GetTargetThreadIDFromProcName?
¿Podrías poner el código completo e indicar que compilador estas usando?
saludos.
Hola fary, gracias por la respuesta.
GetTargetThreadIDFromProcName es GetPIDFromProcName que lo cambié el nombre para que fuera más sencillo, eso ha sido un fallo de edición, es simplemente una función que devuelve el PID de un proceso que le pasas como argumento. Es GetPIDFromProcName vamos XD.
El caso es el compilador y que no se como usar el debugger para pillar las direcciones de las funciones y en qué puede ayudarme a pesar de que he estado buscando sobre ello.
Uso visual studio 2013 (v120). El compilador es derivado de g++ es propio de VS. Calculo el tamaño de la función con delimitandola con otra función static, pero ese método inestable para calcular el tamaño de la función dependiendo del compilador. Es probable que el mismo código funcione en codeblocks sin problemas. Pero en caso de ser eso lo que falle, ¿como puedo arreglarlo?, ¿dónde debería de inspeccionar?.
Seguiré probando más adelante con la versión release y otros compiladores, pero tengo que hacerlo con el de VS.
Un saludo.
Edito: Buenas acabo de probar el código en codeblocks y funciona sin problemas, codeblocks usa g++ y para C gcc si no mal recuerdo. Luego no es problema del código, es del compilador.
Me alegro de que hallas podido solucionar el problema.
En este caso podrías haber mirado lo que sucedia abriendo el ejecutable en cuestion en el que se va a inyectar el código con OllyDbg y poniendo en BP en la API MessageBoxA. Al inyectar el código se te pararía el programa y podrías ver donde esta el error.
saludos.
Bueno solucionado todavía no está, aunque si he confirmado que el problema tiene que ver con el compilador como suponía, luego el código está bien.
Ahora, creo que se puede solucionar de las siguientes maneras:
- Cargando el código a inyectar ya compilado en una variable e inyectar desde ella (no me acaba de gustar, pero ahí esta).
- Cambiando de compilador, el compilador de visual studio creo que ofusca el código y es por eso que falla, con otro funcionaría. Pero aún así no se podrian usar crypters ni nada por el estilo con el ejecutable, ya que al acceder al código a inyectar si esta ofuscado no funcionaría (aunque dependería del crypter algunos si), y eso es buena **.
- Como tú dices abriendo el ejecutable con el ollydbg, pero si por cada vez que lo vuelvo a compilar o cada cambio que añado tengo que estar haciendo eso para que funcione y buscando las direcciones de memoria y tal, tampoco me parece un buen método, pero es lo que más me convence aunque ahora mismo no sabría como hacerlo.
El problema de la inyección de código es: ¿es compatible con crypters?.
Luego me pondré a mirar como va eso del ollydbg a ver si encuentro algo X"D
Saludos!.
Aqui tienes un código de ejemplo en C funcional.
https://foro.elhacker.net/net/inyeccion_dll_sin_dll_by_e0n_problema_edicion_de_memoria_convertir_a_c-t267355.0.html
Se puede inyectar código que tengas almacenado en una variable, sí, eso se llama Shellcode.
Con lo de los cripters te refieres si se puede cifrar el exe que inyecta?
No se trata del compilador exactamente, sino de características del código compilado (el compilador añade cosas caprichosamente que se pueden desactivar/remover [?]).
Deberías revisar las instrucciones de la función a inyectar mediante IDA o algún debugger. Lo más probable es que encuentres al menos un CALL a una dirección de memoria, situado posteriormente al MessageBoxA, "perteneciente" al 'inyector' y no a chrome.exe.
La función a la que intenta llamar el thread corresponde a _RTC_CheckEsp (al menos en VS2015). Pertenece a un conjunto de funciones que agrega el compilador para reportar errores en run-time, y se encuentra dentro del mismo ejecutable compilado.
Te recomiendo visitar este enlace para que conozcas con más detalle sobre lo que es RTC (Run-Time Error Checking) y cómo desactivarlo: https://msdn.microsoft.com/en-us/library/8wtf2dfz.aspx
Culpar al compilador de que tu código falle me parece muy chulito......
Cita de: fary en 7 Abril 2016, 21:12 PM
Aqui tienes un código de ejemplo en C funcional.
https://foro.elhacker.net/net/inyeccion_dll_sin_dll_by_e0n_problema_edicion_de_memoria_convertir_a_c-t267355.0.html
ésos son códigos.......
has probado a reservar memoria como hace él/ella????
Cita de: burbu_1 en 8 Abril 2016, 18:08 PM
Culpar al compilador de que tu código falle me parece muy chulito......
ésos son códigos.......
has probado a reservar memoria como hace él/ella????
:huh: no entiendo tu post :s
Lo más fácil y mejor es que suba el ejecutable que genera y lo revisamos desde un debugger...
Saludos!!
Pues yo insisto en que el problema son las verificaciones run-time que agrega VS a las funciones.
Quité Run-Time Error Checking en las opciones del proyecto, compilé el programa (con VS2015), y no hubieron más crashes.
Función inyectada con RTC activado:
023C0000 55 PUSH EBP
023C0001 8BEC MOV EBP,ESP
023C0003 81EC DC000000 SUB ESP,0DC
023C0009 53 PUSH EBX
023C000A 56 PUSH ESI
023C000B 57 PUSH EDI
023C000C 8DBD 24FFFFFF LEA EDI,DWORD PTR SS:[EBP-DC]
023C0012 B9 37000000 MOV ECX,37
023C0017 B8 CCCCCCCC MOV EAX,CCCCCCCC
023C001C F3:AB REP STOS DWORD PTR ES:[EDI]
023C001E 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
023C0021 8B08 MOV ECX,DWORD PTR DS:[EAX]
023C0023 894D F8 MOV DWORD PTR SS:[EBP-8],ECX
023C0026 8BF4 MOV ESI,ESP
023C0028 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
023C002B 8B48 50 MOV ECX,DWORD PTR DS:[EAX+50]
023C002E 51 PUSH ECX
023C002F 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8]
023C0032 83C2 36 ADD EDX,36
023C0035 52 PUSH EDX
023C0036 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
023C0039 83C0 04 ADD EAX,4
023C003C 50 PUSH EAX
023C003D 6A 00 PUSH 0
023C003F FF55 F8 CALL DWORD PTR SS:[EBP-8]
023C0042 3BF4 CMP ESI,ESP
023C0044 E8 09E6FFFF CALL 023BE652 ; _RTC_CheckEsp
023C0049 8945 EC MOV DWORD PTR SS:[EBP-14],EAX
023C004C 8B45 EC MOV EAX,DWORD PTR SS:[EBP-14]
023C004F 8985 24FFFFFF MOV DWORD PTR SS:[EBP-DC],EAX
023C0055 33C0 XOR EAX,EAX
023C0057 5F POP EDI
023C0058 5E POP ESI
023C0059 5B POP EBX
023C005A 81C4 DC000000 ADD ESP,0DC
023C0060 3BEC CMP EBP,ESP
023C0062 E8 EBE5FFFF CALL 023BE652 ; _RTC_CheckEsp
023C0067 8BE5 MOV ESP,EBP
023C0069 5D POP EBP
023C006A C3 RETN
Función inyectada sin RTC:
023A0000 55 PUSH EBP
023A0001 8BEC MOV EBP,ESP
023A0003 83EC 4C SUB ESP,4C
023A0006 53 PUSH EBX
023A0007 56 PUSH ESI
023A0008 57 PUSH EDI
023A0009 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
023A000C 8B08 MOV ECX,DWORD PTR DS:[EAX]
023A000E 894D FC MOV DWORD PTR SS:[EBP-4],ECX
023A0011 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
023A0014 8B48 50 MOV ECX,DWORD PTR DS:[EAX+50]
023A0017 51 PUSH ECX
023A0018 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8]
023A001B 83C2 36 ADD EDX,36
023A001E 52 PUSH EDX
023A001F 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]
023A0022 83C0 04 ADD EAX,4
023A0025 50 PUSH EAX
023A0026 6A 00 PUSH 0
023A0028 FF55 FC CALL DWORD PTR SS:[EBP-4]
023A002B 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
023A002E 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8]
023A0031 8945 B4 MOV DWORD PTR SS:[EBP-4C],EAX
023A0034 33C0 XOR EAX,EAX
023A0036 5F POP EDI
023A0037 5E POP ESI
023A0038 5B POP EBX
023A0039 8BE5 MOV ESP,EBP
023A003B 5D POP EBP
023A003C C3 RETN
Bueno siento no haber respondido antes, pero estoy ocupado sin embargo he ido leyendo poco a poco los mensajes, y ahora he hecho un hueco para responder.
El código como dije funcionaba el codeblocks luego no era problema de código, iba a probar a compilarlo release, y buscar la función que se inyectaba aunque si bine la primera por tiempo, la segunda no tuve suerte.
He probado lo que decía pinkiepie de desactivar el RTC y ha funcionado a la primera. ¡BRAVOO!
Así que muchas gracias a todos, en especial a pinkiepie, bienvenido al foro que te has creado cuenta solo para responder parece XD, un abrazo.
Cuando tenga tiempo estudiaré a fondo el tema, y me pondré con hexadecimal y ollydbg.
Saludos.