Cheat Engine Forum Index Cheat Engine
The Official Site of Cheat Engine
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 


[C++] Process Viewer.

 
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming
View previous topic :: View next topic  
Author Message
Cx
Master Cheater
Reputation: 0

Joined: 27 Jul 2007
Posts: 367

PostPosted: Tue May 27, 2008 11:22 pm    Post subject: [C++] Process Viewer. Reply with quote

A very basic process viewer with no functions besides, well, viewing processes.

Code & binary attatched.

Please go through the code and tell me if anything is inefficient/should be fixed.
And be very picky; this is the framework for a little project I'm doing and I don't want to start off with bad code.

For those of you who don't want to download:
pastebin

EDIT:
I made a change so that it displays the process ID as well, however I'm not sure that I did it the best way possible (with the string buffer... eh. >___<)
Here is the new function, please look it over:
Code:
void UpdateProcessList(HWND hList)
{
   WCHAR szList[MAX_PATH]; //NEW// ... but pe32.szExeFile's size is MAX_PATH also...
   HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
   PROCESSENTRY32 pe32;
   pe32.dwSize = sizeof(PROCESSENTRY32);
   Process32First(hSnapshot, &pe32);
   SendMessage(hList, LB_RESETCONTENT, NULL, NULL);
   do {
      wsprintf(szList, _T("%s  [%d]"), pe32.szExeFile, pe32.th32ProcessID); //NEW//
      SendMessage(hList, LB_ADDSTRING, NULL, (LPARAM)szList); //NEW//
      //OLD// SendMessage(hList, LB_ADDSTRING, NULL, (LPARAM)pe32.szExeFile);
   } while(Process32Next(hSnapshot, &pe32));
   CloseHandle(hSnapshot);
}



The Extension 'rar' was deactivated by an board admin, therefore this Attachment is not displayed.


_________________

armed with this small butterfly net
i will face the world alone
& never be lonely.
Back to top
View user's profile Send private message
SXGuy
I post too much
Reputation: 0

Joined: 19 Sep 2006
Posts: 3551

PostPosted: Wed May 28, 2008 3:16 am    Post subject: Reply with quote

Dude, you should try something like this.

Shows all hidden processes and modules, even if they are unlinked from the eprocess.

[code]//*********************************************************************************************

#include <ntddk.h>
#include <ndis.h>
#include <stdio.h>
#include <windef.h>


//*********************************************************************************************
// Type definitions
//
//*********************************************************************************************
#define VERSION "0.2-beta1"

typedef struct _MODULE_ENTRY {
LIST_ENTRY link; // Flink, Blink
BYTE unknown1[16];
DWORD imageBase;
DWORD entryPoint;
DWORD imageSize;
UNICODE_STRING drvPath;
UNICODE_STRING drvName;
//...
} MODULE_ENTRY, *PMODULE_ENTRY;


#pragma pack(1)
typedef struct ServiceDescriptorEntry {
PDWORD ServiceTable;
PDWORD CounterTableBase;
DWORD ServiceLimit;
PBYTE ArgumentTable;
} SDT;
#pragma pack()


#define DRV_NAME KProcCheck

#define _DRV_LINK(_name) \\DosDevices\\ ##_name
#define _DRV_DEVICE(_name) \\Device\\ ##_name
#define DRV_DEVICE _DRV_DEVICE(DRV_NAME)
#define DRV_LINK _DRV_LINK(DRV_NAME)

#define _CSTRING(_text) #_text
#define CSTRING(_text) _CSTRING (_text)

#define _USTRING(_text) L##_text
#define USTRING(_text) _USTRING (_text)


#define PRESET_UNICODE_STRING(_var,_buffer) \
UNICODE_STRING _var = \
{ \
sizeof (USTRING (_buffer)) - sizeof (WORD), \
sizeof (USTRING (_buffer)), \
USTRING (_buffer) \
};


PRESET_UNICODE_STRING(gDeviceName, CSTRING(DRV_DEVICE));
PRESET_UNICODE_STRING(gSymbolicLinkName, CSTRING(DRV_LINK));


//*********************************************************************************************
// Exported symbols that we need.
//
//*********************************************************************************************

NTKERNELAPI NTSTATUS KeSetAffinityThread(long lParam1, long lParam2);

NTKERNELAPI NTSTATUS KeAddSystemServiceTable(
PVOID lpAddressTable,
BOOLEAN bUnknown,
DWORD dwNumEntries,
PVOID lpParameterTable,
DWORD dwTableID );

__declspec(dllimport) SDT KeServiceDescriptorTable;
__declspec(dllimport) DWORD PsInitialSystemProcess;


//*********************************************************************************************
// ioctl codes
//
//*********************************************************************************************

#define IOCTL_CODE1 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_BUFFERED, FILE_READ_ACCESS + FILE_WRITE_ACCESS)
#define IOCTL_CODE2 CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS + FILE_WRITE_ACCESS)
#define IOCTL_GETVERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_READ_ACCESS + FILE_WRITE_ACCESS)


//*********************************************************************************************
// Globals
//
//*********************************************************************************************
#define NOT_SUPPORTED 0
#define WIN2K 1
#define WINXP 2


PDEVICE_OBJECT gpDeviceObject = NULL;
DWORD gPsLoadedModuleList = 0;
DWORD gSystemProcessActiveLink = 0;
DWORD gProcessNameOffset = 0; // offset from ActiveProcessLinks
DWORD gKernelVersion = NOT_SUPPORTED;
DWORD gKiWaitInListHead = 0;
DWORD gKiWaitOutListHead = 0;
DWORD gXPKiWaitListHead = 0;
DWORD gKiDispatcherReadyListHead = 0;
DWORD gKeServiceDescriptorTableShadow = 0;


//*********************************************************************************************
// FindPsLoadedModuleList - Thanks to fuzen for this technique
//
//*********************************************************************************************

DWORD FindPsLoadedModuleList (IN PDRIVER_OBJECT DriverObject)
{
PMODULE_ENTRY pm_current, first;

if (DriverObject == NULL)
return 0;

__try
{
pm_current = *((PMODULE_ENTRY*)((DWORD)DriverObject + 0x14));
if (pm_current == NULL)
return 0;

first = pm_current;

do
{
if(!MmIsAddressValid((PVOID)pm_current))
break;

//DbgPrint("%.8X %.8X %.8X %S\n", pm_current, pm_current->link.Flink, pm_current->link.Blink, pm_current->drvName.Buffer);
//DbgPrint("%.8X %.8X %.8X %.8X %8X\n", pm_current, pm_current->link.Flink, pm_current->link.Blink, pm_current->entryPoint, pm_current->drvPath.Buffer);
if (!MmIsAddressValid((PVOID)pm_current->entryPoint) || !MmIsAddressValid(pm_current->drvPath.Buffer) ||
!MmIsAddressValid(pm_current->drvName.Buffer))
{
return (DWORD) pm_current;
}
pm_current = (MODULE_ENTRY*)pm_current->link.Flink;
}
while ((PMODULE_ENTRY)pm_current != first);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return 0;
}

return 0;
}


DWORD FindSystemProcessActiveLink(void)
{
DWORD ptr = PsInitialSystemProcess;

if(gKernelVersion == WIN2K)
ptr += 0xa0;
else if(gKernelVersion == WINXP)
ptr += 0x88;
else
return 0;

return ptr;
}


//*********************************************************************************************
// Attempt to locate the non-exported symbols KiWaitInListHead and KiWaitOutListHead by
// scanning in KeWaitForSingleObject API for
//
// mov ecx,0x80482258 <- KiWaitInListHead
// test al,al
//
// And,
// mov ecx, offset dword_0_482808 <- KiWaitOutListHead
//
// Tested on Win2k SP2 and SP4
//*********************************************************************************************

void FindKiWaitInOutListHead(DWORD *waitInListAddr, DWORD *waitOutListAddr)
{
int i;
unsigned char *ptr;
DWORD retVal1 = 0, retVal2 = 0;
ptr = (unsigned char *)KeWaitForSingleObject;

__try
{
for( i = 0; i < PAGE_SIZE; i++ )
{
if(!MmIsAddressValid((PVOID)ptr) || !MmIsAddressValid((PVOID)(ptr+24)))
break;

if(*ptr == 0xb9 && *(ptr+5) == 0x84 && *(ptr+6) == 0xc0 && *(ptr+24) == 0xb9)
{
retVal1 = *(DWORD *)(ptr + 1);
retVal2 = *(DWORD *)(ptr + 25);

break;
}
ptr++;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
retVal1 = 0;
retVal2 = 0;
}

*waitInListAddr = retVal1;
*waitOutListAddr = retVal2;

return;
}


//*********************************************************************************************
// Attempt to locate the non-exported symbol KiDispatcherReadyListHead by
// scanning KeSetAffinityThread for
//
// 8d04cde0224880 lea eax,[nt!KiDispatcherReadyListHead (804822e0)+ecx*8]
// 3900 cmp [eax],eax
//
// Tested on Win2k SP2 and SP4
//*********************************************************************************************

DWORD FindKiDispatcherReadyListHead(void)
{
int i;
unsigned char *ptr;
DWORD retVal = 0;
ptr = (unsigned char *)KeSetAffinityThread;

__try
{
for( i = 0; i < PAGE_SIZE; i++ )
{
if(!MmIsAddressValid((PVOID)ptr) || !MmIsAddressValid((PVOID)(ptr+4)))
break;

if(*ptr == 0x8d && *(ptr+1) == 0x04 && *(ptr+2) == 0xcd && *(ptr+7) == 0x39)
{
retVal = *(DWORD *)(ptr + 3);
break;
}
ptr++;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return 0;
}

return retVal;
}


//*********************************************************************************************
// Attempt to locate the non-exported symbols KiWaitListHead by
// scanning in KeDelayExecutionThread API for
//
// mov dword ptr [ebx], offset _KiWaitListHead
// mov [ebx+4], eax
//
// Tested on WinXP SP1 SP2
//*********************************************************************************************

void FindXPKiWaitListHead(DWORD *waitListAddr)
{
int i;
unsigned char *ptr;
DWORD retVal = 0;
ptr = (unsigned char *)KeDelayExecutionThread;

__try
{
for( i = 0; i < PAGE_SIZE; i++ )
{
if(!MmIsAddressValid((PVOID)ptr) || !MmIsAddressValid((PVOID)(ptr+4)))
break;

if(*ptr == 0xc7 && *(ptr+1) == 0x03 && *(ptr+6) == 0x89 && *(ptr+7) == 0x43)
{
retVal = *(DWORD *)(ptr + 2);

break;
}
ptr++;
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
retVal = 0;
}

*waitListAddr = retVal;

return;
}


//*********************************************************************************************
// Gets the offset to process name, thx to SysInternals for this idea.
// This will not work if driver is loaded using SystemLoadAndCallImage
//
//*********************************************************************************************

DWORD getProcNameOffset(DWORD startPos)
{
DWORD curproc;
int i;
DWORD procNameOffset = 0;

curproc = startPos;

__try
{
for(i = 0; i < PAGE_SIZE; i++)
{
if(MmIsAddressValid((PCHAR) curproc + i) &&
strncmp( "System", (PCHAR) curproc + i, strlen("System")) == 0)
{
procNameOffset = i;
break;
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return 0;
}

return procNameOffset;
}

//*********************************************************************************************
// Find address of KeServiceDescriptorTableShadow by scanning KeAddSystemServiceTable
//
//*********************************************************************************************

DWORD findAddressofShadowTable(void)
{
int i;
unsigned char *p;
DWORD val;

p = (unsigned char *)KeAddSystemServiceTable;

for (i = 0; i < PAGE_SIZE; i++, p++)
{
__try
{
val = *(unsigned int *)p;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
return 0;
}

if (MmIsAddressValid((PVOID)val))
{
if (memcmp((PVOID)val, &KeServiceDescriptorTable, 16) == 0)
{
if((PVOID)val != &KeServiceDescriptorTable)
return val;
}
}
}
return 0;
}



//*********************************************************************************************
// DeviceDispatcher
//
//*********************************************************************************************

NTSTATUS DeviceDispatcher(PIRP pIrp)
{
PIO_STACK_LOCATION esp;
DWORD dInfo = 0;
char *output;
NTSTATUS ntS = STATUS_NOT_IMPLEMENTED;

//DbgPrint("DeviceDispatcher called\n");
esp = IoGetCurrentIrpStackLocation(pIrp);

switch (esp->MajorFunction)
{
case IRP_MJ_CREATE:
//DbgPrint("IRP_MJ_CREATE\n");
ntS = STATUS_SUCCESS;
break;

case IRP_MJ_CLEANUP:
//DbgPrint("IRP_MJ_CLEANUP\n");
ntS = STATUS_SUCCESS;
break;

case IRP_MJ_CLOSE:
//DbgPrint("IRP_MJ_CLOSE\n");
ntS = STATUS_SUCCESS;
break;

case IRP_MJ_DEVICE_CONTROL:
{
DWORD sizeReq;

// returns address of KeServiceDescriptorTable and KeServiceDescriptorTableShadow
if(esp->Parameters.DeviceIoControl.IoControlCode == IOCTL_CODE1)
{
if(esp->Parameters.DeviceIoControl.OutputBufferLength >= 32)
{
DWORD *outDword = (DWORD *)pIrp->AssociatedIrp.SystemBuffer;
if(outDword)
{
outDword[0] = gPsLoadedModuleList;
outDword[1] = (DWORD)&KeServiceDescriptorTable;
outDword[2] = (DWORD)gKeServiceDescriptorTableShadow;
outDword[3] = gSystemProcessActiveLink;
outDword[4] = gProcessNameOffset;
if(gKernelVersion == WIN2K)
{
outDword[5] = gKiWaitInListHead;
outDword[6] = gKiWaitOutListHead;
}
else
{
outDword[5] = gXPKiWaitListHead;
outDword[6] = gXPKiWaitListHead;
}
outDword[7] = gKiDispatcherReadyListHead;


dInfo = 32;
ntS = STATUS_SUCCESS;
}
}
else
ntS = STATUS_INFO_LENGTH_MISMATCH;
}
else if(esp->Parameters.DeviceIoControl.IoControlCode == IOCTL_CODE2)
{
if(esp->Parameters.DeviceIoControl.OutputBufferLength >= 4)
{
DWORD *outDword = (DWORD *)pIrp->AssociatedIrp.SystemBuffer;
if(outDword)
{
PHYSICAL_ADDRESS paddr = MmGetPhysicalAddress((PVOID)outDword[0]);
outDword[0] = paddr.LowPart;
dInfo = 4;
ntS = STATUS_SUCCESS;
}
}
else
ntS = STATUS_INFO_LENGTH_MISMATCH;
}

else if(esp->Parameters.DeviceIoControl.IoControlCode == IOCTL_GETVERSION)
{
if(esp->Parameters.DeviceIoControl.OutputBufferLength >= 16)
{
char *outBuffer = (char *)pIrp->AssociatedIrp.SystemBuffer;
if(outBuffer)
{
memset(outBuffer, 0, 16);
strncpy(outBuffer, VERSION, 16);

dInfo = 16;
ntS = STATUS_SUCCESS;
}
}
else
ntS = STATUS_INFO_LENGTH_MISMATCH;
}

break;
}

default:
break;
}

pIrp->IoStatus.Status = ntS;
pIrp->IoStatus.Information = dInfo;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);

return(ntS);
}


//*********************************************************************************************
// DriverDispatcher
//
//*********************************************************************************************

NTSTATUS DriverDispatcher(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
NTSTATUS ntS = STATUS_INVALID_PARAMETER_1;

//DbgPrint("DriverDispatcher called\n");

if (pDeviceObject == gpDeviceObject)
ntS = DeviceDispatcher(pIrp);

return(ntS);
}


//*********************************************************************************************
// Create our device to communicate with user land
//
//*********************************************************************************************

NTSTATUS createOurDevice(PDRIVER_OBJECT driverObject)
{
PDEVICE_OBJECT pDeviceObject = NULL;
NTSTATUS NTs;
int i;

NTs = IoCreateDevice(driverObject, 0, &gDeviceName,
FILE_DEVICE_UNKNOWN, 0, FALSE, &pDeviceObject);

if(NTs == STATUS_SUCCESS)
{
NTs = IoCreateSymbolicLink(&gSymbolicLinkName, &gDeviceName);

if (NTs == STATUS_SUCCESS)
{
gpDeviceObject = pDeviceObject;

//DbgPrint("Device created successfully. Name = %S\n", gDeviceName.Buffer);
}
else
{
DbgPrint("KProcCheck: Error while creating symbolic link\n");
IoDeleteDevice (pDeviceObject);
}

}
else
{
DbgPrint("KProcCheck: Error while creating device\n");
}

return NTs;
}


//*********************************************************************************************
// DriverUnload - removes our device object
//
//*********************************************************************************************

VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
//DbgPrint("Unloading...\n");

IoDeleteSymbolicLink(&gSymbolicLinkName);

if(gpDeviceObject)
IoDeleteDevice(gpDeviceObject);
}


//*********************************************************************************************
// DriverEntry
//
//*********************************************************************************************

NTSTATUS DriverEntry(PDRIVER_OBJECT driverObject, PUNICODE_STRING RegistryPath)
{
int i;
NTSTATUS ns;
DWORD major, minor, build;
KIRQL kq;

driverObject->DriverUnload = DriverUnload;

PsGetVersion(&major, &minor, &build, NULL);
if(major == 5)
{
if(minor == 0)
gKernelVersion = WIN2K;
else if(minor == 1)
gKernelVersion = WINXP;
}

if(gKernelVersion == NOT_SUPPORTED)
return STATUS_NOT_SUPPORTED;

for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
driverObject->MajorFunction[i] = DriverDispatcher;
}

ns = createOurDevice(driverObject);
if(ns != STATUS_SUCCESS)
{
return ns;
}

kq = KeRaiseIrqlToDpcLevel();

gSystemProcessActiveLink = FindSystemProcessActiveLink();
gProcessNameOffset = getProcNameOffset(gSystemProcessActiveLink);
gPsLoadedModuleList = FindPsLoadedModuleList(driverObject);
gKeServiceDescriptorTableShadow = findAddressofShadowTable();

if(gKernelVersion == WIN2K)
{
FindKiWaitInOutListHead(&gKiWaitInListHead, &gKiWaitOutListHead);
gKiDispatcherReadyListHead = FindKiDispatcherReadyListHead();
}
else if(gKernelVersion == WINXP)
{
FindXPKiWaitListHead(&gXPKiWaitListHead);
}

KeLowerIrql(kq);

/*
DbgPrint("At %.8X\n", gPsLoadedModuleList);
DbgPrint("%.8X\n", IOCTL_CODE1);
DbgPrint("%.8X\n", IOCTL_CODE2);
DbgPrint("%.8X\n", PsInitialSystemProcess);
DbgPrint("%d, %d, %d\n", major, minor, build);
DbgPrint("Version %d\n", gKernelVersion);
DbgPrint("Link %.8X\n", gSystemProcessActiveLink);
DbgPrint("Offset %.8X\n", gProcessNameOffset);
DbgPrint("%s\n", (char *)gSystemProcessActiveLink + gProcessNameOffset);
DbgPrint("%.8X, %.8X\n", gKiWaitInListHead, gKiWaitOutListHead);
DbgPrint("XP -> %.8X\n", gXPKiWaitListHead);
DbgPrint("Code = %.8X\n", IOCTL_GETVERSION);
*/

return(STATUS_SUCCESS);
}
[/code]

PM me for full source if your interested.
Back to top
View user's profile Send private message
HomerSexual
Grandmaster Cheater Supreme
Reputation: 5

Joined: 03 Feb 2007
Posts: 1657

PostPosted: Wed May 28, 2008 5:26 am    Post subject: Reply with quote

Note that is kernel mode and he is in user mode. IF you want to do something like that you have to use IOTCL
_________________
Back to top
View user's profile Send private message
oib111
I post too much
Reputation: 0

Joined: 02 Apr 2007
Posts: 2947
Location: you wanna know why?

PostPosted: Wed May 28, 2008 6:36 am    Post subject: Reply with quote

I would have made a list with headers one for the process name and pid. And for you're pid. I probably would've done this:

Code:

hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
Process32First(hSnapshot, &pe32);
do {
   SendMessage(hList, LB_ADDSTRING, NULL, (LPARAM)pe32.th32ProcessID);
} while(Process32Next(hSnapshot, &pe32));
CloseHandle(hSnapshot);

_________________


8D wrote:

cigs dont make people high, which weed does, which causes them to do bad stuff. like killing
Back to top
View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger
Cx
Master Cheater
Reputation: 0

Joined: 27 Jul 2007
Posts: 367

PostPosted: Wed May 28, 2008 4:56 pm    Post subject: Reply with quote

SX: Thanks, I might implement it.
Oib: ... Then I wouldn't have a process name (or they would be on different lines).

_________________

armed with this small butterfly net
i will face the world alone
& never be lonely.
Back to top
View user's profile Send private message
oib111
I post too much
Reputation: 0

Joined: 02 Apr 2007
Posts: 2947
Location: you wanna know why?

PostPosted: Wed May 28, 2008 5:12 pm    Post subject: Reply with quote

Nonono.

Quote:

A header control is a window that is usually positioned above columns of text or numbers. It contains a title for each column, and it can be divided into parts.



_________________


8D wrote:

cigs dont make people high, which weed does, which causes them to do bad stuff. like killing
Back to top
View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger
Flyte
Peanuts!!!!
Reputation: 6

Joined: 19 Apr 2006
Posts: 1887
Location: Canada

PostPosted: Wed May 28, 2008 5:25 pm    Post subject: Reply with quote

Thanks for that copy and paste SXGuy, you can find almost the exact same code on google, with different variable names.

Looks like a pitiful attempt to cover it up to me.
Back to top
View user's profile Send private message
oib111
I post too much
Reputation: 0

Joined: 02 Apr 2007
Posts: 2947
Location: you wanna know why?

PostPosted: Wed May 28, 2008 5:55 pm    Post subject: Reply with quote

Isn't that also part of process hunter's code?
_________________


8D wrote:

cigs dont make people high, which weed does, which causes them to do bad stuff. like killing
Back to top
View user's profile Send private message AIM Address Yahoo Messenger MSN Messenger
lurc
Grandmaster Cheater Supreme
Reputation: 2

Joined: 13 Nov 2006
Posts: 1900

PostPosted: Wed May 28, 2008 6:50 pm    Post subject: Reply with quote

oib111 wrote:
Isn't that also part of process hunter's code?


No.

_________________
Back to top
View user's profile Send private message
Cx
Master Cheater
Reputation: 0

Joined: 27 Jul 2007
Posts: 367

PostPosted: Fri May 30, 2008 5:21 pm    Post subject: Reply with quote

oib111 wrote:
Nonono.

Quote:

A header control is a window that is usually positioned above columns of text or numbers. It contains a title for each column, and it can be divided into parts.




Cool, never even thought about that. thanks.

_________________

armed with this small butterfly net
i will face the world alone
& never be lonely.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Cheat Engine Forum Index -> General programming All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001, 2005 phpBB Group

CE Wiki   IRC (#CEF)   Twitter
Third party websites