Forum programistyczne DevStart – reaktywacja

Forum programistyczne DevStart wystartowało w 2013 roku z wielkim hukiem, zyskując spore poparcie na serwisach, takich jak Wykop.

Niestety, ograniczenia systemu, który wspierał działanie forum – spowodowały, że użytkownicy po mału odchodzili, na co przyczyniły się m.in. brak powiadomień, brak prywatnych wiadomości i inne mniejsze i większe utrudnienia.

Wczoraj forum stanęło nowo na nogi, na nowym silniku, jest nowy design, wersja jest przyjazna urządzeniom mobilnym, zachęcam wszystkich, którzy spisali projekt na stary na odwiedziny.

Forum programistyczne DevStartPS. Reklama pochodzi z Magazynu Programista z 2013 roku, stąd „nowe forum”.

Październikowa zamuła

Jesień w toku, zimno jak cholera, dlatego kilka ciekawych rzeczy, na które ostatnio natrafiłem.

Mateusz Jurczyk vel j00ru znalazł sporo błędów w IDA, co opisał w swojej prezentacji na:

https://j00ru.vexillium.org/?p=2454

Na blogu Grzegorza Anotniaka znajdzicie ciekawy artykuł o tzw. globbingu, naprawdę interesująca lektura dla kogoś, kto tworzy narzędzia wykorzystywane z linii komend:

http://anadoxin.org/blog/blog/20141016/enabling-globbing-in-a-console-win32-application/

Gynvael Coldwind jak zwykle nie zawodzi i na jego blogu znajdziecie tutorial ze Strefy CTF (seria artykułów dla magazynu Programista):

http://gynvael.coldwind.pl/?id=545

Sebastien Andrivet opublikował obfuscator dla C++ bazujący na metaprogramowaniu, coś co kiedyś kolega deus próbował zaimplementować bez skutku:

https://github.com/andrivet/ADVobfuscator

Michał Grzegorzewski napisał artykuł o wykorzystaniu nowego narzędzia od Microsoft – Sysmon. Oprócz tego, jeśli przejrzycie jego blog to możecie się zdziwić ile ciekawych wpisów na temat internalsów Windowsa popełnił:

http://zine.net.pl/blogs/mgrzeg/archive/2014/10/17/sysmon.aspx

Z innych ciekawych rzeczy, o których w sumie niedawno się dowiedziałem i co mnie zaskoczyło to zakończenie produkcji exe-protectora i systemu licencyjnego Armadillo aka Software Passport:

http://www.siliconrealms.com/

Świeczka na drogę [i] w postaci uniwersalnego unpackera dilloDIE 😛

Fabian “ryg” Giesen znany koder z grupy demoscenowej Farbrausch napisał o wadach i zaletach systemów little i big endian oczami programisty:

http://fgiesen.wordpress.com/2014/10/25/little-endian-vs-big-endian/

Jak napisać skomplikowany patch?

Nawiązując do artykułu Jak napisać prosty patch? i komentarzy @ img (hi mate), prezentuję bardziej rozbudowaną wersję patchera z całą gamą sprawdzania potencjalnych błędów. Jeśli zauważycie więcej potencjalnych kłopotów – piszcie w komentarzach (sam jestem ciekaw, co jeszcze może pójść nie tak w jak się wydaje prostej operacji).

#define UNICODE

#include <windows.h>
#include <Sfc.h>

// zalacz biblioteke SFC.lib (mechanizm ochrony plikow systemowych WFP / WRP)
#pragma comment(lib, "sfc")

int main()
{
	// pelna sciezka pliku do spatchowania
	const wchar_t * wszFilePath = L"C:\\plik.exe";

	// bajty, ktore zostana zapisane do pliku
	const BYTE cPatch[] = { 0xAA, 0xBB, 0xCC };

	// offset, pod ktorym zostana zapisane powyzsze bajty
	const DWORD dwPatchRawOffset = 0x1234;

	// rozmiar pliku
	DWORD dwFileSize = 0;

	// ilosc zapisanych bajtow w pliku (parametr dla funkcji WriteFile)
	DWORD dwWritten = 0;

	// kod bledu z funkcji zapisu do pliku WriteFile
	BOOL bWriteFileResult = FALSE;

	// sprawdz czy plik ma atrybuty read only lub znajduje sie na nosniku jak np. DVD
	DWORD dwFileAttributes = GetFileAttributes(wszFilePath);

	// czy udalo sie odczytac atrybuty?
	if (dwFileAttributes == INVALID_FILE_ATTRIBUTES)
	{
		MessageBox(NULL, L"Nie mozna odczytac atrybutow pliku (plik nie istnieje?)!", L"Blad", MB_ICONERROR);
		return 1;
	}

	// czy plik ma atrybuty tylko do odczytu?
	if ( (dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0)
	{
		MessageBox(NULL, L"Wybrany plik nie ma praw do zapisu (lub znajduje sie na takim nosniku jak np. DVD)!", L"Blad", MB_ICONERROR);
		return 2;
	}

	// czy plik jest chronionym plikiem systemowym?
	if (SfcIsFileProtected(NULL, wszFilePath) == TRUE)
	{
		MessageBox(NULL, L"Wybrany plik jest chronionym plikiem systemowym i automatycznie zostanie odtworzony po zmianie przez system Windows!", L"Blad", MB_ICONERROR);
		return 3;
	}

	// otworz plik wejsciowy w trybie do zapisu (flaga GENERIC_WRITE)
	HANDLE hFile = CreateFile(wszFilePath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	// jesli nie udalo sie otworzyc pliku - wyswietl komunikat i zakoncz
	if (hFile == INVALID_HANDLE_VALUE)
	{
		MessageBox(NULL, L"Nie udalo sie otworzyc pliku wejsciowego!", L"Blad", MB_ICONERROR);
		return 4;
	}

	// pobierz rozmiar pliku
	dwFileSize = GetFileSize(hFile, NULL);

	// czy plik jest pusty?
	if (dwFileSize == 0)
	{
		CloseHandle(hFile);

		MessageBox(NULL, L"Plik jest pusty (0 bajtow)!", L"Blad", MB_ICONERROR);
		return 5;
	}

	// czy wskaznik pliku, gdzie ma byc spatchowany przekracza rozmiar pliku?
	if ( (dwPatchRawOffset + sizeof(cPatch)) > dwFileSize)
	{
		CloseHandle(hFile);

		MessageBox(NULL, L"Wskaznik do spatchowania znajduje sie poza rozmiarem pliku!", L"Blad", MB_ICONERROR);
		return 6;
	}

	// ustaw wskaznik pliku na offsecie (raw offset),
	// gdzie zostana zapisane zmodyfikowane bajty
	if (SetFilePointer(hFile, dwPatchRawOffset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
	{
		CloseHandle(hFile);

		MessageBox(NULL, L"Nie udalo sie ustawic wskaznika do spatchowania w wybranym pliku!", L"Blad", MB_ICONERROR);
		return 7;
	}

	// pod wskazanym adresem zapisz bajty z tablicy cPatch
	bWriteFileResult = WriteFile(hFile, cPatch, sizeof(cPatch), &dwWritten, NULL);

	// czy udalo sie zapisac do pliku?
	if (bWriteFileResult == FALSE)
	{
		CloseHandle(hFile);

		MessageBox(NULL, L"Wystapil blad zapisu do pliku!", L"Blad", MB_ICONERROR);
		return 8;
	}

	// czy zapisane zostaly wszystkie bajty patcha?
	if (dwWritten != sizeof(cPatch))
	{
		CloseHandle(hFile);

		MessageBox(NULL, L"Nie udalo sie zapisac wszystkich bajtow!", L"Blad", MB_ICONERROR);
		return 9;
	}

	// zapisz wyniki na dysk
	if (FlushFileBuffers(hFile) == FALSE)
	{
		CloseHandle(hFile);

		MessageBox(NULL, L"Nie udalo sie zapisac zmian na dysk!", L"Blad", MB_ICONERROR);
		return 10;
	}

	// zamknij plik
	CloseHandle(hFile);

	MessageBox(NULL, L"Plik zostal pomyslnie zmodyfikowany", L"Informacja", MB_ICONINFORMATION);

	return 0;
}

Źródła w języku angielskim zostały także opublikowane na https://github.com/PELock/Patch-File-Example

Jak odczytać pamięć klucza sprzętowego ROCKEY2?

ROCKEY2 jest prostym kluczem sprzętowym (tzw. dongle), wykorzystywanym Klucz sprzętowy ROCKEY2m.in. w systemach licencyjnych oprogramowania.

Całe zabezpieczenie opiera się także na envelope (czyli exe-protectorze), jednak ze względu na prostotę tego konkretnego modelu klucza nie polecałbym jego stosowania w zabezpieczeniu oprogramowania.

ROCKEY2 posiada wbudowaną pamięć, składającą się z 5 bloków po 512 bajtów każdy.

Poniżej znajdziecie kod pozwalający odczytać wszystkie banki pamięci klucza. Wymagana jest do tego znajomość poprawnego identyfikatora użytkownika (uid), a do kompilacji potrzebne Wam będzie SDK tegoż klucza.

#include <windows.h>
#include <stdio.h>
#include "Rockey2.h"

// prosta funkcja zapisujaca zawartosc bufora do pliku
void save_file(char *file_name, char *buffer_bytes, size_t buffer_size)
{
	FILE *file_handle = NULL;

	file_handle = fopen(file_name, "wb+");

	fwrite(buffer_bytes, 1, buffer_size, file_handle);

	fclose(file_handle);
}

// zapisuje wybrany blok pamieci klucza Rockey2 do pliku
void dump_rockey2_block(int key_handle, int block_index, char *file_name)
{
	BYTE buffer_bytes[512] = { 0 };

	int result = 0;

	result = RY2_Read(key_handle, block_index, buffer_bytes);

	save_file(file_name, buffer_bytes, sizeof(buffer_bytes));
}

int main(int argc, char **argv)
{
	// liczba znalezionych kluczy
	int keys_count = 0;

	// uchwyt otworzonego klucza
	int key_handle = 0;

	int i = 0;

	// identyfikator klucza potrzebny do jego otwarcia
	DWORD uid = 0x12345678;

	DWORD hid = 0;

	printf("[i] memory dumper dla kluczy Rockey2 - www.secnews.pl\n");

	// znajdz aktualnie dostepne klucze Rockey2
	keys_count = RY2_Find();

	if (keys_count == 0)
	{
		printf("[!] nie znaleziono zadnych kluczy Rockey!");
		return 1;
	}

	printf("[i] znalezionych kluczy Rockey2 = %i\n", keys_count);

	// otworz klucz korzystajac z parametru UID
	key_handle = RY2_Open(1, uid, &hid);

	if (key_handle < 0)
	{
		printf("[!] nie udalo sie uzyskac dostepu do klucza (bledny uid?)!");
		return 2;
	}

	printf("[i] uchwyt klucza = %08X, HardwareId = %08X\n", key_handle, hid);

	// odczytaj wybrane bloki pamieci klucza
	// Rockey2 posiada 5 blokow po 512 bajtow kazdy
	dump_rockey2_block(key_handle, 0, "block_dump_0.bin");
	//dump_rockey2_block(key_handle, 1, "block_dump_1.bin");
	//dump_rockey2_block(key_handle, 2, "block_dump_2.bin");
	//dump_rockey2_block(key_handle, 3, "block_dump_3.bin");
	//dump_rockey2_block(key_handle, 4, "block_dump_4.bin");

	// zamknij klucz
	RY2_Close(0);

	return 0;
}

 

Jak napisać prosty patch?

Dzisiaj coś dla początkujących, czyli krótki program w C/C++, prezentujący jak używając funkcji WinApi napisać prosty patch, który otworzy wskazany plik i zmodyfikuje kilka bajtów pod konkretnym adresem.

#include <windows.h>

int main()
{
	// bajty, ktore zostana zapisane do pliku
	BYTE cPatch[] = { 0xAA, 0xBB, 0xCC };

	// offset, pod ktorym zostana zapisane powyzsze bajty
	const DWORD dwPatchRawOffset = 0x1234;

	// ilosc zapisanych bajtow w pliku (parametr dla funkcji WriteFile)
	DWORD dwWritten = 0;

	// uchwyt pliku
	HANDLE hFile = INVALID_HANDLE_VALUE;

	// otworz plik wejsciowy w trybie do zapisu (flaga GENERIC_WRITE)
	hFile = CreateFile("plik.exe", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	// jesli nie udalo sie otworzyc pliku - wyswietl komunikat i zakoncz
	if (hFile == INVALID_HANDLE_VALUE)
	{
		MessageBox(NULL, "Nie udalo sie otworzyc pliku wejsciowego!", "Blad", MB_ICONERROR);
		return 1;
	}

	// ustaw wskaznik pliku na offsecie (raw offset),
	// gdzie zostana zapisane zmodyfikowane bajty
	SetFilePointer(hFile, dwPatchRawOffset, 0, FILE_BEGIN);

	// pod wskazanym adresem zapisz bajty z tablicy cPatch
	WriteFile(hFile, cPatch, sizeof(cPatch), &dwWritten, NULL);

	// zamknij plik
	CloseHandle(hFile);

	MessageBox(NULL, "Plik zostal pomyslnie zmodyfikowany", "Informacja", MB_ICONINFORMATION);

	return 0;
}

Źródła w języku angielskim zostały opublikowane na https://github.com/PELock/Simple-Patch-File-Example

PS. Być może ktoś zechce w komentarzach zaprezentować jak taki prosty patch wyglądałby w innych językach programowania. Jestem ciekaw waszych interpretacji oraz usprawnień.