Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Marathon: arriva il Fortnite hardcore
Marathon: arriva il Fortnite hardcore
Marathon è il titolo multiplayer competitivo del momento. Ecco quali sono le caratteristiche di gioco principali, insieme alle nostre prime considerazioni dopo qualche "run" nell'extraction shooter di Bungie
HP Imagine 2026: abbiamo visto HP IQ all’opera, ecco cosa può (e non può) fare
HP Imagine 2026: abbiamo visto HP IQ all’opera, ecco cosa può (e non può) fare
A New York HP ha messo al centro della scena HP IQ, la piattaforma di IA locale da 20 miliardi di parametri. L’abbiamo vista in funzione: è uno strumento che funziona, pensato per un target specifico, con vantaggi reali e limiti altrettanto evidenti
PNY RTX 5080 Slim OC, sembra una Founders Edition ma non lo è
PNY RTX 5080 Slim OC, sembra una Founders Edition ma non lo è
La PNY GeForce RTX 5080 Slim OC si distingue nel panorama delle GPU di fascia alta per il design compatto a due slot, ispirato alla NVIDIA GeForce RTX 5080 Founders Edition. In questo test analizziamo comportamento termico e prestazioni in gioco, valutando se il formato ridotto comprometta o meno l'esperienza complessiva rispetto alle soluzioni più ingombranti presenti sul mercato.
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 12-12-2005, 20:45   #1
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
una fork per Windows [x ilsensine, ma non solo :)]

l'altro giorno sulla mailing list del corso di Laboratorio di SO arriva un niubbo e fa: "ho fatto per esercitarmi un programma che usa la funzione fork bla bla e su Windows non compila (lol ) esiste una funzione analoga alla fork su Windows?"; dopodiché arriva un altro niubbo (un po' meno niubbo del precedente però) e fa "ah bla bla bla la fork è una prerogativa dei sistemi Unix ecc. ecc.".
allora io prendo spunto e realizzo una mini-fork per Windows
non vi immaginate che sia un granché, è molto rudimentale: altro non fa che creare il processo figlio sospeso, ricopiarci tutte le sezioni non shared e non discardable impostate con permessi di scrittura oltre che di lettura, settare opportunamente il contesto del thread interrotto, ed infine riesumarlo; una fork simile funziona solo a patto che siano verificate le seguenti condizioni:
1) il programma è single-threaded
2) il programma non chiama VirtualAlloc e HeapAlloc prima della fork (dopo volendo si, ma prima no)
3) il programma non alloca handles non ereditabili prima della fork (dopo magari si, ma prima no )

comunque quel poco che fa lo fa bene
siccome ricordo che ilsensine una volta chiese a fek di spiegargli come hanno fatto quelli di Cygwin a realizzare la fork su Windows, ora la incollo qui di seguito; BTW, per l'occasione mi sono anche letto il codice della fork di Cygwin: la loro funziona un po' meglio della mia perché hanno un vantaggio: se ho ben capito come funziona questo Cygwin, si assume che un programma usi solamente le funzioni di Cygwin, quindi loro nel realizzare la fork avevano controllo sull'heap; ma per fare un bel crash anche su Cygwin è sufficiente tenere memoria di un handle non ereditabile prima di una fork

Codice:
#include <windows.h>

int fork();

int main() {
	TCHAR pszMsg[0x100];
	wsprintf(pszMsg, TEXT("questo è il processo padre, PID = %d"), GetCurrentProcessId());
	MessageBox(NULL, pszMsg, TEXT("fork on Windows"), MB_ICONINFORMATION);

	if (fork()) {
		wsprintf(pszMsg, TEXT("questo invece è il figlio, PID = %d"), GetCurrentProcessId());
		MessageBox(NULL, pszMsg, TEXT("fork on Windows"), MB_ICONINFORMATION);
	}

	return 0;
}


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

HANDLE hStarted = NULL;

__declspec(naked) void Stub() {
	SetEvent(hStarted);
	CloseHandle(hStarted);
	SuspendThread(GetCurrentThread());
}

BYTE pbJmp[5] = {0xE9};

int fork() {
	DWORD dwDummy;

	TCHAR pszFileName[0x400];
	if (!GetModuleFileName(NULL, pszFileName, 0x400)) {
		return -1;
	}

	SECURITY_ATTRIBUTES sa = {
		sizeof(SECURITY_ATTRIBUTES),
		NULL,
		TRUE
	};
	hStarted = CreateEvent(&sa, FALSE, FALSE, NULL);

	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory((PVOID)&si, sizeof(STARTUPINFO));
	si.cb = sizeof(STARTUPINFO);

	if (!CreateProcess(pszFileName, NULL, NULL, NULL, TRUE, GetPriorityClass(GetCurrentProcess()) |
		CREATE_SUSPENDED, NULL, NULL, &si, &pi))
	{
		return -1;
	}

	WriteProcessMemory(pi.hProcess, (PVOID)&hStarted, (PVOID)&hStarted, 4, &dwDummy);


	PBYTE pbInstBase = (PBYTE)GetModuleHandle(NULL);
	PIMAGE_NT_HEADERS pinth = (PIMAGE_NT_HEADERS)(pbInstBase + *(PDWORD)(pbInstBase + 0x3C));

	PVOID pvEntryAddress = (PVOID)(pbInstBase + pinth->OptionalHeader.AddressOfEntryPoint);

	DWORD dwPrevProtect;
	VirtualProtectEx(pi.hProcess, pvEntryAddress, 5, PAGE_READWRITE, &dwPrevProtect);

	*(PDWORD)(pbJmp + 1) = (DWORD)&Stub - (DWORD)pvEntryAddress - 5;
	WriteProcessMemory(pi.hProcess, pvEntryAddress, (PVOID)pbJmp, 5, &dwDummy);

	ResumeThread(pi.hThread);
	WaitForSingleObject(hStarted, INFINITE);
	CloseHandle(hStarted);

	WriteProcessMemory(pi.hProcess, pvEntryAddress, pvEntryAddress, 5, &dwDummy);

	VirtualProtectEx(pi.hProcess, pvEntryAddress, 5, dwPrevProtect, &dwDummy);


	PIMAGE_SECTION_HEADER pSecHdrs = (PIMAGE_SECTION_HEADER)((PBYTE)pinth +
		sizeof(IMAGE_NT_HEADERS));
	for (UINT u = 0; u < pinth->FileHeader.NumberOfSections; u++) {
		DWORD dwFlags = pSecHdrs[u].Characteristics;
		if (!TESTFLAG(dwFlags, IMAGE_SCN_MEM_DISCARDABLE) &&
			!TESTFLAG(dwFlags, IMAGE_SCN_MEM_SHARED) &&
			TESTFLAG(dwFlags, IMAGE_SCN_MEM_READ) &&
			TESTFLAG(dwFlags, IMAGE_SCN_MEM_WRITE))
		{
			PVOID pvSecAddr = (PVOID)(pbInstBase + pSecHdrs[u].VirtualAddress);
			WriteProcessMemory(pi.hProcess, pvSecAddr, pvSecAddr, pSecHdrs[u].Misc.VirtualSize,
				&dwDummy);
		}
	}


	BOOL InTheChild = FALSE;

	CONTEXT c;
	ZeroMemory((PVOID)&c, sizeof(CONTEXT));
	c.ContextFlags = CONTEXT_FULL;
	GetThreadContext(GetCurrentThread(), &c);

	__asm {
		call near here
here:
		pop eax
		inc eax
		mov c.Eip,eax
		mov c.Esp,esp
		mov c.Ebp,ebp
	}

	if (InTheChild) {
		return GetCurrentProcessId();
	}

	/*
	PUSH EBP
	MOV EBP,ESP
	*/

	DWORD dwFramePtr;
	__asm {
		mov dwFramePtr,ebp
	}
	DWORD dwKernel32 = (DWORD)LoadLibrary(TEXT("kernel32.dll"));
	PIMAGE_NT_HEADERS pinthKernel32 = (PIMAGE_NT_HEADERS)(dwKernel32 +
		*(PDWORD)(dwKernel32 + 0x3C));
	UINT uKernel32Size = pinthKernel32->OptionalHeader.SizeOfImage;
	while (dwFramePtr) {
		DWORD dwRetAddress = *(((PDWORD)dwFramePtr) + 1);
		if ((UINT)(dwRetAddress - dwKernel32) <= uKernel32Size) {
			break;
		}
		dwFramePtr = *(PDWORD)dwFramePtr;
	}

	DWORD dwStackPtr;
	__asm {
		mov dwStackPtr,esp
	}
	DWORD dwDelta = dwFramePtr - dwStackPtr;

	WriteProcessMemory(pi.hProcess, (PVOID)dwStackPtr, (PVOID)dwStackPtr, dwDelta, &dwDummy);


	BOOL RemoteChildFlag = TRUE;
	WriteProcessMemory(pi.hProcess, (PVOID)&InTheChild, (PVOID)&RemoteChildFlag, 4, &dwDummy);

	SetThreadContext(pi.hThread, &c);
	ResumeThread(pi.hThread);

	CloseHandle(pi.hThread);
	CloseHandle(pi.hProcess);

	return 0;
}
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 12-12-2005, 20:49   #2
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
dimenticavo: a causa di una particolarità del mio codice, il programma che chiama quella fork non può neanche chiamarla da una funzione di callback che è stata a sua volta richiamata da Kernel32.dll: altre DLL vanno bene, User32 ad esempio va bene, ma Kernel32 no
insomma sta fork fa abbastanza schifo
ma provate voi a farne una migliore su Windows

però c'è di buono che in teoria un programma che usa quella fork può anche avere un'interfaccia grafica perché gli handles delle finestre sono globalmente visibili, e quindi sarebbero validi anche nei processi figli... con l'unico problema che il processo figlio utilizzerebbe le stesse finestre del padre ci sarebbe un'attimino di interferenza
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 12-12-2005, 21:51   #3
The3DProgrammer
Senior Member
 
Iscritto dal: May 2000
Messaggi: 1459
certo ke tu e kernel32.dll vi parlate eh?


ciau
The3DProgrammer è offline   Rispondi citando il messaggio o parte di esso
Old 12-12-2005, 21:59   #4
VegetaSSJ5
Senior Member
 
L'Avatar di VegetaSSJ5
 
Iscritto dal: Sep 2002
Città: Celano (AQ) Segno_Zodiacale: Leone Ascendente: Cammello Segni_Particolari: Quello
Messaggi: 9571



VegetaSSJ5 è offline   Rispondi citando il messaggio o parte di esso
Old 12-12-2005, 22:17   #5
jappilas
Senior Member
 
L'Avatar di jappilas
 
Iscritto dal: Apr 2003
Città: Genova
Messaggi: 4747
bello, bello, tutta "arte che entra"

ancora inpùt, ancora...
__________________
Jappilas is a character created by a friend for his own comic - I feel honored he allowed me to bear his name
Saber's true name belongs to myth - a Heroic Soul out of legends, fighting in our time to fullfill her only wish
Let her image remind of her story, and of the emotions that flew from my heart when i assisted to her Fate
jappilas è offline   Rispondi citando il messaggio o parte di esso
Old 12-12-2005, 22:21   #6
The3DProgrammer
Senior Member
 
Iscritto dal: May 2000
Messaggi: 1459
a grandi linee l'ho capita, mi manca solo una parte:


Codice:

	*(PDWORD)(pbJmp + 1) = (DWORD)&Stub - (DWORD)pvEntryAddress - 5;
	WriteProcessMemory(pi.hProcess, pvEntryAddress, (PVOID)pbJmp, 5,      &dwDummy);
Ad occhio, &Stub-pvEntryAddress-5(?) restituisce il numero di byte che comprende la sezione tra l'entry point e la funzione Stub (di cui nn capisco la necessità di dichiararla naked) di cui vai ad effettuare una copia nel nuovo processo... o no?

ciau
The3DProgrammer è offline   Rispondi citando il messaggio o parte di esso
Old 12-12-2005, 23:10   #7
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
Quote:
Originariamente inviato da The3DProgrammer
a grandi linee l'ho capita, mi manca solo una parte:


Codice:

	*(PDWORD)(pbJmp + 1) = (DWORD)&Stub - (DWORD)pvEntryAddress - 5;
	WriteProcessMemory(pi.hProcess, pvEntryAddress, (PVOID)pbJmp, 5,      &dwDummy);
Ad occhio, &Stub-pvEntryAddress-5(?) restituisce il numero di byte che comprende la sezione tra l'entry point e la funzione Stub (di cui nn capisco la necessità di dichiararla naked) di cui vai ad effettuare una copia nel nuovo processo... o no?
hum, se non hai capito quello ti manca un pezzo piuttosto grosso... ti do un aiutino: guarda il nome del buffer che conteine i dati che vado a copiare nell'altro processo, e guarda anche la dimensione di tale buffer e il valore del primo byte

ciao
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 12-12-2005, 23:14   #8
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
Quote:
Originariamente inviato da VegetaSSJ5



capisco lo stupore, ma come mai le lacrime?
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 13-12-2005, 08:17   #9
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
Quote:
Originariamente inviato da 71104
1) il programma è single-threaded
Come mai questa limitazione? Una fork non clona i thread

Quote:
comunque quel poco che fa lo fa bene
Non dovrebbe fare molto altro, in effetti. Tieni conto che il 90% delle fork viene fatto prima di una exec (visto che nei sistemi unix non esiste un equivalente di CreateProcess), e il 9.9% sono situazioni che potrebbero essere meglio gestite tramite i thread. Direi quindi che se si intende scrivere un programma multipiattaforma che giri anche su windows, ha molto senso aggiungere quel paio di righe su #ifdef per chiamare CreateProcess oppure fork+exec a seconda della piattaforma (nascoste magari in un metodo StartNewProcess() ). Anche perché con le varie WriteProcessMemory elimini il principale punto di forza della fork (ovvero la COW), rendendo quindi estremamente inefficiente la funzione.

Grazie per la spiegazione comunque
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
Old 13-12-2005, 08:50   #10
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
Quote:
Originariamente inviato da 71104
3) il programma non alloca handles non ereditabili prima della fork (dopo magari si, ma prima no )
Anche questo non dovrebbe essere un problema, se la fork viene usata nella maniera classica (fork+exec). Anche su linux gli fd possono essere marcati "non ereditabili da una exec". In questo caso, gli handler non ereditabili dovrebbero passare inosservati/inuilizzati.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
Old 13-12-2005, 18:31   #11
VegetaSSJ5
Senior Member
 
L'Avatar di VegetaSSJ5
 
Iscritto dal: Sep 2002
Città: Celano (AQ) Segno_Zodiacale: Leone Ascendente: Cammello Segni_Particolari: Quello
Messaggi: 9571
Quote:
Originariamente inviato da 71104
capisco lo stupore, ma come mai le lacrime?
ops hai ragione! ho dimenticato anche questo -->
VegetaSSJ5 è offline   Rispondi citando il messaggio o parte di esso
Old 13-12-2005, 22:56   #12
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
Quote:
Originariamente inviato da ilsensine
Come mai questa limitazione? Una fork non clona i thread
appunto
il nuovo programma non avrà i thread del primo, avrà solo il thread primario, quindi o il programma è single threaded oppure il programmatore deve essere consapevole della limitazione.

Quote:
Non dovrebbe fare molto altro, in effetti. Tieni conto che il 90% delle fork viene fatto prima di una exec (visto che nei sistemi unix non esiste un equivalente di CreateProcess), e il 9.9% sono situazioni che potrebbero essere meglio gestite tramite i thread. Direi quindi che se si intende scrivere un programma multipiattaforma che giri anche su windows, ha molto senso aggiungere quel paio di righe su #ifdef per chiamare CreateProcess oppure fork+exec a seconda della piattaforma (nascoste magari in un metodo StartNewProcess() ).
si ma che utilità ha secondo te questa fork che non ti permette neanche di usare malloc e free??

Quote:
Anche perché con le varie WriteProcessMemory elimini il principale punto di forza della fork (ovvero la COW), rendendo quindi estremamente inefficiente la funzione.
era solo un esperimento didattico

Quote:
Grazie per la spiegazione comunque
prego
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 13-12-2005, 22:58   #13
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
Quote:
Originariamente inviato da ilsensine
Anche questo non dovrebbe essere un problema, se la fork viene usata nella maniera classica (fork+exec). Anche su linux gli fd possono essere marcati "non ereditabili da una exec". In questo caso, gli handler non ereditabili dovrebbero passare inosservati/inuilizzati.
il problema è il seguente:
1) il processo padre crea un handle non ereditabile per, diciamo, un file, e non lo chiude
2) fork
3) il processo figlio fa riferimento a quell'handle...

al punto 3 qualsiasi funzione API semplicemente ritorna errore, ma il processo ne deve essere "aware"; cioè, se tu mi dici che il problema esiste anche su Linux e che i programmatori che usano la fork ne sono coscienti allora va bene, volevo solo dire che è un punto da tenere presente...

Ultima modifica di 71104 : 13-12-2005 alle 23:00.
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 14-12-2005, 07:45   #14
ilsensine
Senior Member
 
L'Avatar di ilsensine
 
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
Quote:
Originariamente inviato da 71104
appunto
il nuovo programma non avrà i thread del primo, avrà solo il thread primario, quindi o il programma è single threaded oppure il programmatore deve essere consapevole della limitazione.
Anche la fork funziona così; un processo forkato contiene un solo thread.

Quote:
si ma che utilità ha secondo te questa fork che non ti permette neanche di usare malloc e free??
<me gnurant>
Vuoi dire che questo:
Quote:
2) il programma non chiama VirtualAlloc e HeapAlloc prima della fork
implica che non puoi chiamare malloc/free? Oh bè questo è un problema...
Quote:
3) il processo figlio fa riferimento a quell'handle...
Se l'handle non è ereditabile è corretto che il figlio lo veda chiuso
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al
andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12
ilsensine è offline   Rispondi citando il messaggio o parte di esso
Old 14-12-2005, 10:02   #15
71104
Bannato
 
L'Avatar di 71104
 
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
Quote:
Originariamente inviato da ilsensine
implica che non puoi chiamare malloc/free? Oh bè questo è un problema...
esatto... ^^
il problema è che su Windows un processo crea uno o più heap usando HeapCreate (poi li distruggerà con HeapDestroy), e in ciascuno di questi può allocare e riallocare memoria con HeapAlloc e HeapRealloc; siccome è anche possibile enumerare tutti gli heap presenti nel processo, io potrei anche provare ad enumerarli e allocare tanti blocchi nel nuovo quanti ne vedo nel vecchio, ma non è detto che avrebbero tutti gli stessi indirizzi virtuali: servirebbero delle rilocazioni... il problema si può risolvere utilizzando VirtualAlloc al posto di HeapAlloc per allocare i blocchi dell'heap: VirtualAlloc infatti permette di specificare l'indirizzo virtuale desiderato, ma c'è un problema anche qui: gli heap in Windows sono oggetti del kernel, ovvero sono identificati da un handle, il quale ovviamente viene creato come non ereditabile; se fosse ereditabile sarebbe un gran macello perché il processo figlio accederebbe alla stessa memoria dinamica del padre senza sincronizzarsi... d'altra parte però, non essendo ereditabile, il processo figlio non vede gli handle degli heap che aveva il padre, e quindi (siccome si suppone che esso tenga memoria dell'handle dell'heap, magari all'interno del CRT di Visual C++) qualsiasi HeapAlloc, HeapRealloc ed HeapFree per lui fallirà.
in user mode insomma non si va molto lontano, a meno che non si faccia come hanno fatto su Cygwin, ovvero non si realizza un intero framework che abbia controllo su queste cose e quindi abbia anche controllo sugli handle degli heap e li possa cambiare a piacere.
quindi stavo pensando l'altro giorno a quale potrebbe essere una soluzione un po' migliore realizzata in kernel mode: in kernel mode dopo aver creato il processo si potrebbe fare un po' quello che fa Linux, ovvero ricopiare pari pari la directory e le tabelle delle pagine mettendole in protezione Copy-On-Write; il problema degli handle degli heap però rimane comunque... uqesta soluzione altro non sarebbe che una versione più efficiente della soluzione in cui uso VirtualAlloc per ricopiare gli heap nel processo figlio.
71104 è offline   Rispondi citando il messaggio o parte di esso
Old 14-12-2005, 14:06   #16
DanieleC88
Senior Member
 
L'Avatar di DanieleC88
 
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
O bella questa...
__________________

C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai!
DanieleC88 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Marathon: arriva il Fortnite hardcore Marathon: arriva il Fortnite hardcore
HP Imagine 2026: abbiamo visto HP IQ all’opera, ecco cosa può (e non può) fare HP Imagine 2026: abbiamo visto HP IQ all’opera, ...
PNY RTX 5080 Slim OC, sembra una Founders Edition ma non lo è PNY RTX 5080 Slim OC, sembra una Founders Editio...
Wi-Fi 7 con il design di una vetta innevata: ecco il nuovo sistema mesh di Huawei Wi-Fi 7 con il design di una vetta innevata: ecc...
Core Ultra 7 270K Plus e Core Ultra 7 250K Plus: Intel cerca il riscatto ma ci riesce in parte Core Ultra 7 270K Plus e Core Ultra 7 250K Plus:...
GeForce RTX 3080 raffreddata con un diss...
Proofpoint mette in sicurezza gli agenti...
Annunci falsi su Bakeca con dati veri di...
Attenzione alla truffa dell'assegno di A...
Addio al mito delle batterie a stato sol...
400 milioni e un obiettivo ambizioso: Re...
TCL 2026: la tecnologia SQD-Mini LED arr...
Gli aggiornamenti arriveranno, ma non si...
Monopattini elettrici: addio "Far W...
Mistral AI raccoglie 830 milioni di doll...
Hacker iraniani di Handala violano la Gm...
Chi è Eddie Dalton: il cantante d...
OVHcloud mette l'Italia al centro della ...
Zeekr 007 GT sold out in Cina, si passa ...
Hisense QLED 4K da 98'' e 85'' con 144Hz...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 17:31.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Served by www3v