diff --git a/Contrib/System/Buffers.c b/Contrib/System/Buffers.c new file mode 100644 index 00000000..d373d8e9 --- /dev/null +++ b/Contrib/System/Buffers.c @@ -0,0 +1,93 @@ +#include "stdafx.h" +#include "Plugin.h" +#include "System.h" +#include "Buffers.h" + +PLUGINFUNCTION(AllocCopy) + int mem; + + if (popint(&mem) == 0) + { + pushint(0); + return; + } + + mem = (int) GlobalCopy((HANDLE) mem); + pushint(mem); +PLUGINFUNCTIONEND + +PLUGINFUNCTION(Alloc) + int size; + int mem; + + if (popint(&size) == 0) + { + pushint(0); + return; + } + + mem = (int) GlobalAlloc(GPTR, size); + pushint(mem); +PLUGINFUNCTIONEND + +PLUGINFUNCTION(Free) + int mem; + + if ((popint(&mem) == 0) || (mem == 0)) + { + pushstring("false"); + return; + } + if ((GlobalFree((HANDLE) mem) == NULL)) pushstring("true"); + else pushstring("false"); +PLUGINFUNCTIONEND + +/*typedef BOOL (__stdcall *GetDiskSpace) +( + LPCTSTR lpDirectoryName, // directory name + PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller + PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk + PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk +);*/ + +/*PLUGINFUNCTION(MyFunction) + GetDiskSpace proc; + ULARGE_INTEGER i1, i2, i3; + BOOL check; + + proc = (GetDiskSpace) GetProcAddress(GetModuleHandle("kernel32.dll"), "GetDiskFreeSpaceExA"); + check = proc(NULL, &i1, &i2, &i3); + + _asm + { + push ecx + lea ecx, i3 + push ecx + lea ecx, i2 + push ecx + lea ecx, i1 + push ecx + push 0 + + call proc + + mov check, eax +// add esp, 16 + pop ecx + } + + char buf[1024]; + wsprintf(buf,"$0=%s\n",getuservariable(INST_0)); + MessageBox(g_hwndParent,buf,0,MB_OK); +PLUGINFUNCTIONEND*/ + +HANDLE GlobalCopy(HANDLE Old) +{ + SIZE_T size; + HANDLE n; + + size = GlobalSize(Old); + n = GlobalAlloc(GPTR, size); + CopyMemory(n, Old, size); + return n; +} \ No newline at end of file diff --git a/Contrib/System/Buffers.h b/Contrib/System/Buffers.h new file mode 100644 index 00000000..538c481b --- /dev/null +++ b/Contrib/System/Buffers.h @@ -0,0 +1,3 @@ +#pragma once + +extern HANDLE GlobalCopy(HANDLE Old); \ No newline at end of file diff --git a/Contrib/System/Last Comments.txt b/Contrib/System/Last Comments.txt new file mode 100644 index 00000000..acd135cc --- /dev/null +++ b/Contrib/System/Last Comments.txt @@ -0,0 +1,23 @@ +I'm just finished and going to sleep, so a few words only. +This is alpha release, just for testing. Report bugs please. + +That version limits: + +0. I've not noticed the NSIS team inverted the 'calling convention', arguments +are passing to stack from left to right during d::p call, so you should invert +system.txt arguments order. See SystemEx.nsi for examples. + +1. PT_VOID and PT_BOOLEAN are unsupported. +2. PT_LONG without Pointer specifier is not allowed. +3. NSIS->Call PT_LONG converts as 32 bits. Back conversion bit-width is unknown. +By the way NSIS doesn't support int64 operations, so you can process received +long values as strings only... +4. Generaly untested :) +5. Requires MSVC++ 7.0 to compile :) Sorry.... + +Todo (will be done in a few days): +1. Structures work (thru functions). +2. Callbacks. +3. Arg-lists +4. Cdecl convention +5. Optimizations and so on... \ No newline at end of file diff --git a/Contrib/System/Plugin.c b/Contrib/System/Plugin.c new file mode 100644 index 00000000..1e0d2174 --- /dev/null +++ b/Contrib/System/Plugin.c @@ -0,0 +1,109 @@ +#include "stdafx.h" +#include "Plugin.h" +#include "System.h" + +HWND g_hwndParent; +int g_stringsize; +stack_t **g_stacktop; +char *g_variables; + +int popstring(char *str) +{ + stack_t *th; + if (!g_stacktop || !*g_stacktop) return 0; + th=(*g_stacktop); + lstrcpy(str,th->text); + *g_stacktop = th->next; + GlobalFree((HGLOBAL)th); + return 1; +} + +void pushstring(char *str) +{ + stack_t *th; + if (!g_stacktop) return; + th=(stack_t*)GlobalAlloc(GPTR,sizeof(stack_t)+g_stringsize); + lstrcpyn(th->text,str,g_stringsize); + th->next=*g_stacktop; + *g_stacktop=th; +} + +char *getuservariable(int varnum) +{ + if (varnum < 0 || varnum >= __INST_LAST) return NULL; + return g_variables+varnum*g_stringsize; +} + +void setuservariable(int varnum, char *var) +{ + if (var != NULL && varnum >= 0 && varnum < __INST_LAST) { + lstrcpy (g_variables + varnum*g_stringsize, var); + + } +} + +int myatoi(char *s) +{ + unsigned int v=0; + if (*s == '0' && (s[1] == 'x' || s[1] == 'X')) + { + s+=2; + for (;;) + { + int c=*s++; + if (c >= '0' && c <= '9') c-='0'; + else if (c >= 'a' && c <= 'f') c-='a'-10; + else if (c >= 'A' && c <= 'F') c-='A'-10; + else break; + v<<=4; + v+=c; + } + } + else if (*s == '0' && s[1] <= '7' && s[1] >= '0') + { + s++; + for (;;) + { + int c=*s++; + if (c >= '0' && c <= '7') c-='0'; + else break; + v<<=3; + v+=c; + } + } + else + { + int sign=0; + if (*s == '-') { s++; sign++; } + for (;;) + { + int c=*s++ - '0'; + if (c < 0 || c > 9) break; + v*=10; + v+=c; + } + if (sign) return -(int) v; + } + return (int)v; +} + +int popint(int *value) +{ + char buffer[1024]; + if (popstring(buffer) == 0) return FALSE; + *value = myatoi(buffer); + return TRUE; +} + +void pushint(int value) +{ + char buffer[1024]; + wsprintf(buffer, "%d", value); + pushstring(buffer); +} + +#ifdef _DEBUG +void main() +{ +} +#endif \ No newline at end of file diff --git a/Contrib/System/Plugin.h b/Contrib/System/Plugin.h new file mode 100644 index 00000000..d8e84626 --- /dev/null +++ b/Contrib/System/Plugin.h @@ -0,0 +1,56 @@ +#pragma once + +typedef struct _stack_t { + struct _stack_t *next; + char text[1]; // this should be the length of string_size +} stack_t; + +enum +{ +INST_0, // $0 +INST_1, // $1 +INST_2, // $2 +INST_3, // $3 +INST_4, // $4 +INST_5, // $5 +INST_6, // $6 +INST_7, // $7 +INST_8, // $8 +INST_9, // $9 +INST_R0, // $R0 +INST_R1, // $R1 +INST_R2, // $R2 +INST_R3, // $R3 +INST_R4, // $R4 +INST_R5, // $R5 +INST_R6, // $R6 +INST_R7, // $R7 +INST_R8, // $R8 +INST_R9, // $R9 +INST_CMDLINE, // $CMDLINE +INST_INSTDIR, // $INSTDIR +INST_OUTDIR, // $OUTDIR +INST_EXEDIR, // $EXEDIR +INST_LANG, // $LANGUAGE +__INST_LAST +}; + +#define PLUGINFUNCTION(name) void __declspec(dllexport) name(HWND hwndParent, int string_size, char *variables, stack_t **stacktop) { \ + g_hwndParent=hwndParent; \ + g_stringsize=string_size; \ + g_stacktop=stacktop; \ + g_variables=variables; { +#define PLUGINFUNCTIONEND }} + +extern char *getuservariable(int varnum); +extern void setuservariable(int varnum, char *var); +extern int popstring(char *str); // 0 on empty stack +extern void pushstring(char *str); +extern int myatoi(char *s); +extern int popint(int *value); // 0 on empty stack +extern void pushint(int value); + +extern HWND g_hwndParent; +extern int g_stringsize; +extern stack_t **g_stacktop; +extern char *g_variables; diff --git a/Contrib/System/System.c b/Contrib/System/System.c new file mode 100644 index 00000000..56efb3c4 --- /dev/null +++ b/Contrib/System/System.c @@ -0,0 +1,390 @@ +// System.cpp : Defines the entry point for the DLL application. +// + +#include "stdafx.h" +#include "Plugin.h" +#include "System.h" + +HINSTANCE g_hInstance; + +#define PT_STRING_SIZE 2048 +#define PARAMOKCHECK(expr) if (expr) { pushint(0); return; } + +PLUGINFUNCTION(PartAddr) + char buffer[1024]; + SystemProc *proc; + + // Retrieve ProcID + PARAMOKCHECK(popstring(buffer) == 0); + // Try to initialize proc ... + proc = ParseProc(buffer); + // ... and return it to nsis! + pushint((int) proc); +PLUGINFUNCTIONEND + +PLUGINFUNCTION(FullAddr) + char procid[1024], paramid[1024]; + SystemProc *proc; + + // Retrieve ProcID and ParamId + PARAMOKCHECK((popstring(procid) == 0) || (popstring(paramid) == 0)) + // Try to initialize proc ... + proc = ParseProc(procid); + PARAMOKCHECK(proc == NULL) + // Try to initialize params ... + PARAMOKCHECK(ParseParam(proc, paramid) == FALSE) + // ... and return it to nsis! + pushint((int) proc); +PLUGINFUNCTIONEND + +PLUGINFUNCTION(ShortAddr) + char paramid[1024]; + SystemProc *proc; + + // Retrieve Proc and ParamId + PARAMOKCHECK((popint(&((int)proc)) == 0) || (popstring(paramid) == 0)) + // Try to initialize params ... + PARAMOKCHECK(ParseParam(proc, paramid) == FALSE) + // ... and return it to nsis! + pushint((int) proc); +PLUGINFUNCTIONEND + +PLUGINFUNCTION(Call) + SystemProc *proc; + + // Retrieve Proc + PARAMOKCHECK(popint(&((int)proc)) == 0) + + // Run the proc + SystemCall(proc); +PLUGINFUNCTIONEND + +PLUGINFUNCTION(ShortCall) + char paramid[1024]; + SystemProc *proc; + + // Retrieve Proc and ParamId + PARAMOKCHECK((popint(&((int)proc)) == 0) || (popstring(paramid) == 0)) + // Try to initialize params ... + PARAMOKCHECK(ParseParam(proc, paramid) == FALSE) + + // Run the proc + SystemCall(proc); +PLUGINFUNCTIONEND + +PLUGINFUNCTION(FullCall) + char procid[1024], paramid[1024]; + SystemProc *proc; + + // Retrieve ProcID and ParamId + PARAMOKCHECK((popstring(procid) == 0) || (popstring(paramid) == 0)) + // Try to initialize proc ... + proc = ParseProc(procid); + PARAMOKCHECK(proc == NULL) + // Try to initialize params ... + PARAMOKCHECK(ParseParam(proc, paramid) == FALSE) + // ... and return it to nsis! + + // Run the proc + SystemCall(proc); + + // We've created it, we've to destroyit + GlobalFree(proc); +PLUGINFUNCTIONEND + +SystemProc *ParseProc(char *ProcID) +{ + SystemProc *proc; + char dllname[1024], procname[256], *p1, *p2; + + // Extract dllname + p1 = ProcID; + p2 = dllname; + while (*p1 && (*p1 != '?')) *(p2++) = *(p1++); + *p2 = 0; + if ((lstrlen(dllname) == 0) || (*p1 == 0)) return NULL; + + // Extract procname + p1++; + p2 = procname; + while (*p1 && (*p1 != '?')) *(p2++) = *(p1++); + *p2 = 0; + if ((lstrlen(procname) == 0) || (*p1 == 0)) return NULL; + + // Ok, check If there is at least 1 param + p1++; + if (*p1 == 0) return NULL; + + // Allocate memory for new Proc + proc = (SystemProc*) GlobalAlloc(GPTR, sizeof(SystemProc)); + + // Ok, retrieve dll handle + proc->dll = GetModuleHandle(dllname); + if (proc->dll == NULL) + { + // Dll is not loaded already + proc->dll = LoadLibrary(dllname); + if (proc->dll == NULL) + { + // Dll not found + GlobalFree(proc); + return NULL; + } + } + + // Dll succesfully loaded, now we should Get Proc Address + proc->proc = GetProcAddress(proc->dll, procname); + if (proc->proc == NULL) + { + // Proc is not loaded succesfully + GlobalFree(proc); + return NULL; + } + + // Allright, lets parse parameters + proc->ParamCount = 0; + while (*p1 && (*p1 != '?')) + { + // Memory is initialized to zeros with GlobalAlloc, so we don't need + // to set defaults for Parameters + + // We should check for pointer + if ((*p1 == 'p') || (*p1 == 'P')) + { + proc->Params[proc->ParamCount].IsPointer = TRUE; + // Check for next character to be valid + p1++; + if ((*p1 == 0) || (*p1 == '?')) break; + } + + switch(*p1) + { + case 'v': + case 'V': + proc->Params[proc->ParamCount].Type = PT_VOID; + break; + case 'i': + case 'I': + proc->Params[proc->ParamCount].Type = PT_INT; + break; + case 'l': + case 'L': + proc->Params[proc->ParamCount].Type = PT_LONG; + break; + case 's': + case 'S': + proc->Params[proc->ParamCount].Type = PT_STRING; + break; + case 'b': + case 'B': + proc->Params[proc->ParamCount].Type = PT_BOOLEAN; + break; + }; + + // Move to next character + proc->ParamCount++; + p1++; + } + return proc; +} + +BOOL ParseParam(SystemProc *proc, char *ParamID) +{ + char *p1; + ProcParameter *par; + + par = proc->Params + 1; + p1 = ParamID; + + // Allright, lets parse input parameters + while (*p1 && (*p1 != '?')) + { + if ((*p1 == 's') || (*p1 == 'S')) par->Input = IOT_STACK; + else if ((*p1 == 'n') || (*p1 == 'N')) par->Input = IOT_NONE; + else if ((*p1 >= '0') && (*p1 <= '9')) par->Input = (*p1-'0')+1; + else if ((*p1 >= 'a') && (*p1 <= 'o')) par->Input = (*p1-'a')+11; + else if ((*p1 >= 'A') && (*p1 <= 'O')) par->Input = (*p1-'A')+11; + + // Move to next param & character + par++; + p1++; + } + + if (*p1++ == 0) return TRUE; + par = proc->Params; + + // Allright, lets parse output parameters + while (*p1) + { + if ((*p1 == 's') || (*p1 == 'S')) par->Output = IOT_STACK; + else if ((*p1 == 'n') || (*p1 == 'N')) par->Output = IOT_NONE; + else if ((*p1 >= '0') && (*p1 <= '9')) par->Output = (*p1-'0')+1; + else if ((*p1 >= 'a') && (*p1 <= 'o')) par->Output = (*p1-'a')+11; + else if ((*p1 >= 'A') && (*p1 <= 'O')) par->Output = (*p1-'A')+11; + + // Move to next param & character + par++; + p1++; + } + + return TRUE; +} + +void ParamsInput(SystemProc *proc) +{ + int i; + ProcParameter *par; + char buffer[PT_STRING_SIZE], *realbuf; + + par = proc->Params + 1; + for (i = 1; i < proc->ParamCount; i++, par++) + { + // Step 1: retrive value + if (par->Input == IOT_STACK) popstring(realbuf = buffer); + else if (par->Input > 0) realbuf = getuservariable(par->Input - 1); + else *(realbuf = buffer) = 0; + + // Step 2: place it + switch (par->Type) + { + // TODO: PT_VOID input???? + //case PT_VOID: + case PT_INT: + { + if (par->IsPointer) + { + par->Value = (int) GlobalAlloc(GPTR, sizeof(int)); + *((int*) par->Value) = myatoi(realbuf); + } else par->Value = myatoi(realbuf); + } + break; + case PT_LONG: + { + if (par->IsPointer) + { + par->Value = (int) GlobalAlloc(GPTR, sizeof(ULARGE_INTEGER)); + ((ULARGE_INTEGER*) par->Value)->LowPart = myatoi(realbuf); + ((ULARGE_INTEGER*) par->Value)->HighPart = 0; // TODO: 64 bit atoi conversion + } else; // TODO: PT_LONG direct input???? + } + break; + case PT_STRING: + { + if (par->IsPointer) + { + par->Value = (int) GlobalAlloc(GPTR, sizeof(int)); + *((int*)par->Value) = GlobalAlloc(GPTR, PT_STRING_SIZE); + lstrcpy(*((LPCSTR*) par->Value), realbuf); + } else + { + par->Value = (int) GlobalAlloc(GPTR, PT_STRING_SIZE); + lstrcpy(par->Value, realbuf); + } + } + break; + // TODO: PT_BOOLEAN support ??? + //case PT_BOLEAN: ; + } + } +} + +void ParamsOutput(SystemProc *proc) +{ + int i; + ProcParameter *par; + char buffer[PT_STRING_SIZE]; + + par = proc->Params; + for (i = 0; i < proc->ParamCount; i++, par++) + { + // Step 1: retrieve value + switch (par->Type) + { + case PT_VOID: + { + if (par->IsPointer); // TODO: Pointer To Void Output + else *buffer = 0; + } + break; + case PT_INT: + { + if (par->IsPointer) + { + wsprintf(buffer, "%d", *((int*) par->Value)); + GlobalFree(par->Value); + } else wsprintf(buffer, "%d", par->Value); + } + break; + case PT_LONG: + { + if (par->IsPointer) + { + wsprintf(buffer, "%ld", *((ULARGE_INTEGER*) par->Value)); + GlobalFree(par->Value); + } else; // TODO: PT_LONG direct output???? + } + break; + case PT_STRING: + { + if (par->IsPointer) + { + lstrcpy(buffer, *((LPCSTR*) par->Value)); + GlobalFree(*((int*)par->Value)); + GlobalFree(par->Value); + } else + { + lstrcpy(buffer, par->Value); + GlobalFree((HANDLE) par->Value); + } + } + break; + // TODO: PT_BOOLEAN support ??? + //case PT_BOLEAN: ; + } + + // Step 2: place it + if (par->Output == IOT_STACK) pushstring(buffer); + else if (par->Output > 0) setuservariable(par->Output - 1, buffer); + } +} + +void SystemCall(SystemProc *proc) +{ + int z; + ProcParameter *par; + + // Prepare input arguments + ParamsInput(proc); + + // Push arguments to stack + par = proc->Params+proc->ParamCount-1; + while (par > proc->Params) + { + z = par->Value; + _asm + { + push z + } + par--; + } + + // Call the proc and save return + z = proc->proc; + _asm + { + call z + mov z, eax + } + proc->Params[0].Value = z; + + // Prepare output parameters + ParamsOutput(proc); +} + +BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved) +{ + g_hInstance=hInst; + + return TRUE; +} + diff --git a/Contrib/System/System.h b/Contrib/System/System.h new file mode 100644 index 00000000..55db95be --- /dev/null +++ b/Contrib/System/System.h @@ -0,0 +1,50 @@ +// The following ifdef block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the SYSTEM_EXPORTS +// symbol defined on the command line. this symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// SYSTEM_API functions as being imported from a DLL, whereas this DLL sees symbols +// defined with this macro as being exported. +#pragma once + +#ifdef SYSTEM_EXPORTS +#define SYSTEM_API __declspec(dllexport) +#else +#define SYSTEM_API __declspec(dllimport) +#endif + +// Real world types +#define PT_VOID 0 +#define PT_INT 1 +#define PT_LONG 2 +#define PT_STRING 3 +#define PT_BOOLEAN 4 + +// Input/Output Source/Destination +#define IOT_NONE 0 +#define IOT_STACK -1 +#define IOT_REG 1 + +// Our single proc parameter +typedef struct +{ + int Type; + BOOL IsPointer; + int Value; // it can hold any value + int Input; + int Output; +} ProcParameter; + +// Our single proc +typedef struct +{ + HANDLE dll; + HANDLE proc; + int ParamCount; + ProcParameter Params[20]; // I hope nobody will use more than 20 params +} SystemProc; + +extern SystemProc *ParseProc(char *ProcID); +extern BOOL ParseParam(SystemProc *proc, char *ParamID); +extern void ParamsInput(SystemProc *proc); +extern void ParamsOutput(SystemProc *proc); +extern void SystemCall(SystemProc *proc); diff --git a/Contrib/System/System.ncb b/Contrib/System/System.ncb new file mode 100644 index 00000000..9057ebac --- /dev/null +++ b/Contrib/System/System.ncb @@ -0,0 +1 @@ +Microsoft C/C++ MSF 7.00 diff --git a/Contrib/System/System.sln b/Contrib/System/System.sln new file mode 100644 index 00000000..9268efc2 --- /dev/null +++ b/Contrib/System/System.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "System", "System.vcproj", "{2FB013AB-6FD4-4239-9974-C999F4DFD70C}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {2FB013AB-6FD4-4239-9974-C999F4DFD70C}.Debug.ActiveCfg = Debug|Win32 + {2FB013AB-6FD4-4239-9974-C999F4DFD70C}.Debug.Build.0 = Debug|Win32 + {2FB013AB-6FD4-4239-9974-C999F4DFD70C}.Release.ActiveCfg = Release|Win32 + {2FB013AB-6FD4-4239-9974-C999F4DFD70C}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/Contrib/System/System.txt b/Contrib/System/System.txt new file mode 100644 index 00000000..f6e7d037 --- /dev/null +++ b/Contrib/System/System.txt @@ -0,0 +1,163 @@ + System: NSIS Plugin + +* - I'm a lazy bitch, for *(N) - see comment N at the end of the file. + +I. Introduction. +---------------- + + That plugin will make you virtually unstopable. Now you could call any +DLL procedure or function, i.e. you gain full control over the system. + + If you want to call some proc, you should prepare two proc IDs: the +ProcId and ParamID. Since the System plugin couldn't know the dll proc +parameters and return type, you should find the proc description somewhere (the +best will be .h files, for example from Platform SDK in case of system dlls). +After that you should specify the ProcID: it contains the DLL and proc name, +proc parameters, and proc calling options. + Since the parameters format of proc in DLL never changes (in general), +that ProcID can be defined ones for all times (in include file for example, and +I'm thinking about automatic conversion of some windows headers (winbase.h, +winuser.h ...) to ProcID defines). + + When you want to call the proc, you should prepare the second id, +ParamID. It specifies where the System plugin should find your input values +(registers, stack, etc) and where it should place proc output values. You can +define this id once for installation, or you can use separate declaration at +each call. + +II. ProcID. +----------- + + Ok. Let's learn how to convert function declaration to ProcID. Below +the ProcID format is specified (You can read here *(1) why I'm using '?' as +delimeter): + +"dll?proc?params?options", where: + + - dll - the path (or name) of DLL containing proc (for ex: "kernel32", +"c:\test\super.dll", etc.). + - proc - the proc name itself (warning: the proc name must be specified +in the way it mentioned at dll, for example it may look like "_MyFunction@16". +Other examples: "GetDiskFreeSpaceExA", "GetProcAddress", etc.). + - params - the proc parameters, described below. + - options - the proc options *(2) (for those, who don't want to read my +comments - Currently Unavailable). At least two will be defined later: 'c' & 's' +-> CDECL and STDCALL calling conventions. Should be completly (including +question mark) ommited now. + + Ok, each proc parameter (and return) is presented by single chararacter +(there is only one exception - p character), these character are: + + v - void (generaly for return) + i - int (includes char, byte, short, handles, pointers and so on) + l - long & large integer (know as int64) + s - string (LPCSTR, pointer to first character) + b - boolean (needs/returns 'true':'false') - by the fact this type is + senseless -> usual integer can be used ('0':'1') + + p - pointer specifier -> the proc needs the pointer to type, affects + next char (parameter) [ex: 'pi' - pointer to int] + + Huh, I think that is easily understandable, but there is one IMPORTANT +HINT: the first parameter is RETURN type! + And at last: the pointers. You should remember that if you specify +pointer parameter with 'p' specifier, the System Plugin waits from you and will +return to you BASE TYPE, i.e. for 'pi' it will wait for and return to you +INTEGER. + As I wrote above the options (including calling conventions are +unsupported now), the System Plugin will always call DLL function with STDCALL +(this convention is default for windows procs, for example for procs specified +with WINAPI. CDECL is usually used with WINAPIV declared procs. This V char +stands for variable, or arguments-list -> with CDECL convention the stack after +the function call is cleared by caller, and with STDCALL it is cleared by called +proc ('calee') -> all procs with arguments-lists (such as wsprintf) must use +CDECL). + +IIa. ProcID examples. +--------------------- + + Let's transform some real procs defenitions to ProcIDs: + +1) WINBASEAPI FARPROC WINAPI GetProcAddress(IN HMODULE hModule, + IN LPCSTR lpProcName); + For the start: proc defined with WINAPI - stdcall and thats allright. +Proc return type FARPROC is just another name for proc handle (or address), so +we could use integer type. This proc defined at kernel32.dll, but '.dll' could +be ommited. So... + +"kernel32?GetProcAddress?iis" + + Params: i - return, i - hModule, s - lpProcName. + Simple, huh? + +2) WINBASEAPI BOOL WINAPI GetDiskFreeSpaceExA( IN LPCSTR lpDirectoryName, + OUT PULARGE_INTEGER lpFreeBytesAvailableToCaller, + OUT PULARGE_INTEGER lpTotalNumberOfBytes, + OUT PULARGE_INTEGER lpTotalNumberOfFreeBytes + ); + + At first, If you'll look at MSDN, you will find GetDiskFreeSpaceEx +function, but not with trailing 'A'. This is default Microsoft behaviour for +functions, which have two variants: for ANSI (trailing 'A') and UNICODE +(trailing 'W') respectively. You can meet such functions sometimes, and since +neither NSIS or System Plugin support unicode you should always use version with +trailing 'A'. PULARGE_INTEGER can be represented as (int64*) [pointer to long], +so we will code this ProcID as: + +"kernel32.dll?GetDiskFreeSpaceExA?bsplplpl" + + Params: b - return (boolean); pl, pl, pl - three pointer to long. + + See other examples at System.nsh. + +III. ParamID. +------------- + + Ok, here is ParamID format: + +"input?output" + +Input/Output -> describes places (from where to take and where to put), encoded +by single character too. The first character of output describes the place for +function return. + +Input sources / Output destinations: + Registers $0-$9 -> 0..9 + Registers $R0-$R9 -> a(0) b(1) c(2) d(3) e(4) f(5) g(6) h(7) i(8) j(9) + Additional regs -> k(CmdLine) l(InstDir) m(OutDir) n(ExeDir) o(Lang) + Stack -> s (parameters are poped/pushed in default, right-to-left order) + None -> n (0 (null) for input / specifies no output is required) + +VI. Functions. +-------------- + +Default return - on stack. + +handle = Alloc(bytes) +ok? = Free(handle) +handle = AllocCopy(handle) -> creates a copy + +---------- + +addr = FullAddr(ProcID, ParamID) -> retrieve address for use with Call +Call = FullCall(ProcID, ParamID) -> Direct call + +addr = PartAddr(ProcID) +Call = Call(addr) + +---------- + +Hint: These two change the passed proc, so if you want to preserve original +proc use AllocCopy... + +addr = ShortAddr(addr, ParamID) -> For use if you half defined the proc +Call = ShortCall(addr, ParamID) -> by PartAddr + +---------- + +Comments (don't forget the * meaning :): + 1. I'm using '?' as delimiter just because I need some character to use +as :). The other reason: '?' can't be spotted at dll paths and proc names. + 2. Currently unsupported. Some features, like buffers/structures, +callbacks, different calling conventions, arg-lists, etc should become available +at future releases. \ No newline at end of file diff --git a/Contrib/System/System.vcproj b/Contrib/System/System.vcproj new file mode 100644 index 00000000..37af6d34 --- /dev/null +++ b/Contrib/System/System.vcproj @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Contrib/System/SystemEx.nsi b/Contrib/System/SystemEx.nsi new file mode 100644 index 00000000..41350f16 --- /dev/null +++ b/Contrib/System/SystemEx.nsi @@ -0,0 +1,48 @@ +; This is just an example of System Plugin +; +; Read LastComments.txt and System.txt (unfinished) +; +; (c) BSForce, 2002 + +Name "System Plugin Example" +OutFile "SystemEx.exe" + +Function .onInit + + ; First example: Message box, uses PartAddr, ShortAddr, Call + + System::PartAddr "user32.dll?MessageBoxA?iissi" + Pop $0 + System::ShortAddr "ssss?1nssn" $0 + Pop $0 + System::Call 33 "Example 1" "Just something" 0 $0 + Pop $3 + Pop $2 + MessageBox MB_OK "Result: $1, strings '$2' and '$3'" + System::Free $0 + Pop $0 + + ; Second example: uses FullAddr, Call, incorpotates int64, returns to $INSTDIR + + System::FullAddr "snnn?s1al2" "kernel32.dll?GetDiskFreeSpaceExA?isplplpl" + Pop $0 + System::Call "c:\" $0 + Pop $3 + MessageBox MB_OK "Path '$1', Free '$R0', Total '$INSTDIR', FreeUser '$2', Result $3" + System::Free $0 + Pop $0 + + ; Third example: uses FullCall + + System::FullCall "?9" "kernel32.dll?GetVersion?i" + ; Version aquired, but we wonna built number for example + IntOp $8 $9 / 65536 + MessageBox MB_OK "Aquired windows version: $9 (Build $8)" + + Quit +FunctionEnd + +Section "ThisNameIsIgnoredSoWhyBother?" +SectionEnd + +; eof diff --git a/Contrib/System/stdafx.c b/Contrib/System/stdafx.c new file mode 100644 index 00000000..5c6abfe6 --- /dev/null +++ b/Contrib/System/stdafx.c @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// AnyDLL.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/Contrib/System/stdafx.h b/Contrib/System/stdafx.h new file mode 100644 index 00000000..1f363ded --- /dev/null +++ b/Contrib/System/stdafx.h @@ -0,0 +1,12 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + +// TODO: reference additional headers your program requires here diff --git a/Plugins/System.dll b/Plugins/System.dll new file mode 100644 index 00000000..230a9c35 Binary files /dev/null and b/Plugins/System.dll differ