home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2004 March
/
CMCD0304.ISO
/
Software
/
Freeware
/
Programare
/
nullsoft
/
nsis20.exe
/
Contrib
/
System
/
Source
/
System.c
< prev
next >
Wrap
C/C++ Source or Header
|
2003-09-11
|
40KB
|
1,331 lines
// System.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "Plugin.h"
#include "Buffers.h"
#include "System.h"
#include <crtdbg.h>
// Parse Section Type
#define PST_PROC 0
#define PST_PARAMS 1
#define PST_RETURN 2
#define PST_OPTIONS 3
#define PCD_NONE 0
#define PCD_PROC 1
#define PCD_PARAMS 2
#define PCD_DONE 3 // Just Continue
const int ParamSizeByType[7] = {0, // PAT_VOID (Size will be equal to 1)
1, // PAT_INT
2, // PAT_LONG
1, // PAT_STRING
1, // PAT_WSTRING
1, // PAT_GUID
0}; // PAT_CALLBACK (Size will be equal to 1)
int z1, z2; // I've made them static for easier use at callback procs
int LastStackPlace;
int LastStackReal;
DWORD LastError;
volatile SystemProc *LastProc;
int CallbackIndex;
HINSTANCE g_hInstance;
// Return to callback caller with stack restore
char retexpr[4];
HANDLE retaddr;
char *GetResultStr(SystemProc *proc)
{
char *buf = AllocString();
if (proc->ProcResult == PR_OK) lstrcpy(buf, "ok");
else if (proc->ProcResult == PR_ERROR) lstrcpy(buf, "error");
else if (proc->ProcResult == PR_CALLBACK) wsprintf(buf, "callback%d", proc->CallbackIndex);
return buf;
}
#ifdef SYSTEM_LOG_DEBUG
// System log debuggin turned on
#define SYSTEM_EVENT(a) { _asm { mov logespsave, esp }; LogEvent(a); }
#define SYSTEM_LOG_ADD(a) { lstrcat(syslogbuf, a); }
#define SYSTEM_LOG_POST { lstrcat(syslogbuf, "\n"); WriteToLog(syslogbuf); *syslogbuf = 0; }
HANDLE logfile = NULL;
char syslogbuf[4096] = "";
int logop = 0, logespsave;
void WriteToLog(char *buffer)
{
DWORD written;
char timebuffer[128];
GetTickCount();
if (logfile == NULL) return;
SetFilePointer(logfile, 0, 0, FILE_END);
wsprintf(timebuffer, "%04d %04d.%03d ", (++logop)%10000, (GetTickCount() / 1000) % 10000,
GetTickCount() % 1000);
_RPT0(_CRT_WARN, timebuffer);
_RPT0(_CRT_WARN, buffer);
WriteFile(logfile, timebuffer, lstrlen(timebuffer), &written, NULL);
WriteFile(logfile, buffer, lstrlen(buffer), &written, NULL);
// FlushFileBuffers(logfile);
}
void LogEvent(char *a)
{
char buffer[1024];
wsprintf(buffer, "%s ESP = 0x%08X Stack = 0x%08X Real = 0x%08X", a,
logespsave, LastStackPlace, LastStackReal);
SYSTEM_LOG_ADD(buffer);
}
PLUGINFUNCTION(Debug)
{
char *o1;
o1 = popstring();
if (logfile == NULL)
if (lstrlen(o1) > 0)
{
SYSTEMTIME t;
char buffer[1024], buftime[1024], bufdate[1024];
// Init debugging
logfile = CreateFile(o1, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
SetFilePointer(logfile, 0, 0, FILE_END);
logop = 0;
GetLocalTime(&t);
GetTimeFormat(LOCALE_SYSTEM_DEFAULT, LOCALE_NOUSEROVERRIDE, &t, NULL, buftime, 1024);
GetDateFormat(LOCALE_SYSTEM_DEFAULT, LOCALE_NOUSEROVERRIDE, &t, NULL, bufdate, 1024);
wsprintf(buffer, "System, %s %s [build "__TIME__" "__DATE__"]\n", buftime, bufdate);
WriteToLog(buffer);
} else ;
else
if (lstrlen(o1) > 0)
{
// Log in to log file
WriteToLog(o1);
} else
{
// Stop debugging
WriteToLog("Debug stopped.\n\n\n");
CloseHandle(logfile);
logfile = NULL;
}
} PLUGINFUNCTIONEND
#else
// System log debugging turned off
#define SYSTEM_EVENT(a)
#define SYSTEM_LOG_ADD(a)
#define SYSTEM_LOG_POST
#endif
PLUGINFUNCTION(Get)
{
SystemProc *proc = PrepareProc(FALSE);
SYSTEM_LOG_ADD("Get ");
SYSTEM_LOG_ADD(proc->DllName);
SYSTEM_LOG_ADD("::");
SYSTEM_LOG_ADD(proc->ProcName);
SYSTEM_LOG_ADD("\n");
SYSTEM_LOG_POST;
if ((proc->Options & POPT_ALWRETURN) != 0)
{
// Always return flag set -> return separate proc and result
pushint((int) proc);
GlobalFree(pushstring(GetResultStr(proc)));
} else
{
if (proc->ProcResult != PR_OK)
{
// No always return flag and error result - return result
GlobalFree(pushstring(GetResultStr(proc)));
// If proc is permanent?
if ((proc->Options & POPT_PERMANENT) == 0)
GlobalFree((HANDLE) proc); // No, free it
}
else // Ok result, return proc
pushint((int) proc);
}
} PLUGINFUNCTIONEND
PLUGINFUNCTION(Call)
{
// Prepare input
SystemProc *proc = PrepareProc(TRUE);
SYSTEM_LOG_ADD("Call ");
SYSTEM_LOG_ADD(proc->DllName);
SYSTEM_LOG_ADD("::");
SYSTEM_LOG_ADD(proc->ProcName);
SYSTEM_LOG_ADD("\n");
if (proc->ProcResult != PR_CALLBACK)
ParamAllocate(proc);
ParamsIn(proc);
// Make the call
if (proc->ProcResult != PR_ERROR)
{
switch (proc->ProcType)
{
case PT_NOTHING:
if (proc->ProcResult == PR_CALLBACK)
proc = CallBack(proc);
break;
case PT_PROC:
case PT_VTABLEPROC:
proc = CallProc(proc); break;
case PT_STRUCT:
CallStruct(proc); break;
}
}
// Process output
if ((proc->Options & POPT_ALWRETURN) != 0)
{
// Always return flag set - return separate return and result
ParamsOut(proc);
GlobalFree(pushstring(GetResultStr(proc)));
} else
{
if (proc->ProcResult != PR_OK)
{
ProcParameter pp;
// Save old return param
pp = proc->Params[0];
// Return result instead of return value
proc->Params[0].Value = (int) GetResultStr(proc);
proc->Params[0].Type = PAT_STRING;
// Return all params
ParamsOut(proc);
// Restore old return param
proc->Params[0] = pp;
} else
ParamsOut(proc);
}
if (proc->ProcResult != PR_CALLBACK)
{
// Deallocate params if not callback
ParamsDeAllocate(proc);
// if not callback - check for unload library option
if ((proc->Options & POPT_UNLOAD)
&& (proc->ProcType == PT_PROC)
&& (proc->Dll != NULL))
FreeLibrary(proc->Dll); // and unload it :)
// In case of POPT_ERROR - first pop will be proc error
if ((proc->Options & POPT_ERROR) != 0) pushint(LastError);
}
// If proc is permanent?
if ((proc->Options & POPT_PERMANENT) == 0)
GlobalFree((HANDLE) proc); // No, free it
} PLUGINFUNCTIONEND
PLUGINFUNCTIONSHORT(Int64Op)
{
__int64 i1, i2 = 0, i3, i4;
char *op, *o1, *o2;
char buf[128];
// Get strings
o1 = popstring(); op = popstring();
i1 = myatoi(o1); // convert first arg to int64
if ((*op != '~') && (*op != '!'))
{
// get second arg, convert it, free it
o2 = popstring();
i2 = myatoi(o2);
GlobalFree(o2);
}
// operation
switch (*op)
{
case '+': i1 += i2; break;
case '-': i1 -= i2; break;
case '*': i1 *= i2; break;
case '/':
case '%':
// It's unclear, but in this case compiler will use DivMod rountine
// instead of two separate Div and Mod rountines.
if (i2 == 0) { i3 = 0; i4 = i1; }
else {i3 = i1 / i2; i4 = i1 % i2; }
if (*op == '/') i1 = i3; else i1 = i4;
break;
case '|': if (op[1] == '|') i1 = i1 || i2; else i1 |= i2; break;
case '&': if (op[1] == '&') i1 = i1 && i2; else i1 &= i2; break;
case '^': i1 ^= i2; break;
case '~': i1 = ~i1; break;
case '!': i1 = !i1; break;
case '<': if (op[1] == '<') i1 = i1 << i2; else i1 = i1 < i2; break;
case '>': if (op[1] == '>') i1 = i1 >> i2; else i1 = i1 > i2; break;
case '=': i1 = (i1 == i2); break;
}
// Output and freedom
myitoa64(i1, buf);
pushstring(buf);
GlobalFree(o1); GlobalFree(op);
} PLUGINFUNCTIONEND
__int64 GetIntFromString(char **p)
{
char buffer[128], *b = buffer;
(*p)++; // First character should be skipped
while (((**p >= 'a') && (**p <= 'f')) || ((**p >= 'A') && (**p <= 'F')) || ((**p >= '0') && (**p <= '9')) || (**p == 'X') || (**p == '-') || (**p == 'x') || (**p == '|')) *(b++) = *((*p)++);
*b = 0;
(*p)--; // We should point at last digit
return myatoi(buffer);
}
SystemProc *PrepareProc(BOOL NeedForCall)
{
int SectionType = PST_PROC, // First section is always proc spec
ProcType = PT_NOTHING, // Default proc spec
ChangesDone = 0,
ParamIndex = 0,
temp = 0, temp2, temp3, temp4;
SystemProc *proc = NULL;
char *ibuf, *ib, *sbuf, *cbuf, *cb;
// Retrieve proc specs
cb = (cbuf = AllocString()); // Current String buffer
sbuf = AllocString(); // Safe String buffer
ib = ibuf = popstring(); // Input string
// Parse the string
while (SectionType != -1)
{
// Check for Section Change
ChangesDone = SectionType;
switch (*ib)
{
case 0x0: SectionType = -1; break;
case '#': SectionType = PST_PROC; ProcType = PT_NOTHING; break;
case '(':
SectionType = PST_PARAMS;
// fake-real parameter: for COM interfaces first param is Interface Pointer
ParamIndex = ((ProcType == PT_VTABLEPROC)?(2):(1));
temp3 = temp = 0;
break;
case ')': SectionType = PST_RETURN; temp3 = temp = 0; break;
case '?': SectionType = PST_OPTIONS; temp = 1; break;
}
// Check for changes
if (ChangesDone != SectionType)
{
switch (ChangesDone)
{
case PST_PROC:
*cb = 0;
// Adopt proc
if (proc == NULL)
{
proc = (SystemProc *) GlobalAlloc(GPTR, sizeof(SystemProc));
proc->Options = 0;
proc->ParamCount = 0;
}
// Default parameters
*proc->DllName = 0;
*proc->ProcName = 0;
proc->Dll = NULL;
proc->Proc = NULL;
proc->ProcType = ProcType;
proc->ProcResult = PR_OK;
// Section changed and previos section was Proc
switch (ProcType)
{
case PT_NOTHING:
// Is it previous proc or just unknown proc?
if (cb != cbuf)
{
// Previous proc (for clear up)
SystemProc *pr = NULL;
if (proc != NULL) GlobalFree(proc);
// Get already defined proc
proc = (SystemProc *) myatoi(cbuf);
// Find the last clone at proc queue
while (proc->Clone != NULL) proc = (pr = proc)->Clone;
// Clear parents record for child callback proc
if (pr != NULL) pr->Clone = NULL;
// Never Redefine?
if ((proc->Options & POPT_NEVERREDEF) != 0)
{
// Create new proc as copy
proc = GlobalCopy(proc);
// NeverRedef options is never inherited
proc->Options &= (~POPT_NEVERREDEF) & (~POPT_PERMANENT);
} else proc->Options |= POPT_PERMANENT; // Proc is old -> permanent
}
break;
case PT_PROC:
case PT_VTABLEPROC:
lstrcpy(proc->ProcName, cbuf);
lstrcpy(proc->DllName, sbuf);
break;
case PT_STRUCT:
lstrcpy(proc->ProcName, cbuf);
break;
}
continue;
case PST_PARAMS:
proc->ParamCount = ParamIndex;
case PST_RETURN:
case PST_OPTIONS:
continue;
}
}
// Parse the section
ChangesDone = PCD_NONE;
switch (SectionType)
{
// Proc sections parser
case PST_PROC:
switch (*ib)
{
case ':':
case '-':
// Is it '::'
if ((*(ib) == '-') && (*(ib+1) == '>'))
{
ProcType = PT_VTABLEPROC;
} else
{
if ((*(ib+1) != ':') || (*(ib) == '-')) break;
ProcType = PT_PROC;
}
ib++; // Skip next ':'
if (cb > cbuf)
{
*cb = 0;
lstrcpy(sbuf, cbuf);
} else *sbuf = 0; // No dll - system proc
// Ok
ChangesDone = PCD_DONE;
break;
case '*':
// Structure defenition
ProcType = PT_STRUCT;
ChangesDone = PCD_DONE;
break;
}
break;
// Params and return sections parser
case PST_RETURN:
ParamIndex = 0; // Uses the same logic as PST_PARAMS section
case PST_PARAMS:
temp2 = -1; temp4 = 0; // Our type placeholder
switch (*ib)
{
case ' ':
break;
case '_': // No param cutting specifier
if (proc->ParamCount > ParamIndex) ParamIndex = proc->ParamCount;
temp3 = temp = 0; // Clear parameter options
break;
case ',': // Next param
temp3 = temp = 0; // Clear parameter options
ParamIndex++;
break;
case '&':
temp = 1; break; // Special parameter option
case '*':
temp = -1; break; // Pointer parameter option
// Types
case 'v':
case 'V': temp2 = PAT_VOID; break;
case 'i':
case 'I': temp2 = PAT_INT; break;
case 'l':
case 'L': temp2 = PAT_LONG; break;
case 't':
case 'T': temp2 = PAT_STRING; break;
case 'g':
case 'G': temp2 = PAT_GUID; break;
case 'w':
case 'W': temp2 = PAT_WSTRING; break;
case 'k':
case 'K': temp2 = PAT_CALLBACK; break;
// Input output specifiers
case '.': temp3++; break; // skip specifier
case 'R':
temp4 = ((int) GetIntFromString(&ib))+1;
if (temp4 < 11) temp4 += 10;
break;
case 'r': temp4 = ((int) GetIntFromString(&ib))+1; break; // Register
case '-':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
// Numeric inline
if (temp3 == 0)
{
ib--;
// It's stupid, I know, but I'm too laze to do another thing
myitoa64(GetIntFromString(&(ib)),(char *)(temp4 = (int) AllocString()));
}
break;
case '\"': case '\'': case '`':
// Character inline
{
char start = *ib;
cb = cbuf;
// copy inline
while (!((*(++ib) == start) && (*(ib+1) != start)) && (*ib))
{
if ((*ib) == start) ++ib;
*(cb++) = *(ib);
}
// finish and save
*cb = 0;
temp4 = (int) AllocStr(cbuf);
}
break;
case 's':
case 'S': temp4 = -1; break; // Stack
case 'c':
case 'C': temp4 = INST_CMDLINE+1; break;
case 'd':
case 'D': temp4 = INST_INSTDIR+1; break;
case 'o':
case 'O': temp4 = INST_OUTDIR+1; break;
case 'e':
case 'E': temp4 = INST_EXEDIR+1; break;
case 'a':
case 'A': temp4 = INST_LANG+1; break;
}
// Param type changed?
if (temp2 != -1)
{
proc->Params[ParamIndex].Type = temp2;
proc->Params[ParamIndex].Size = // If pointer, then 1, else by type
(temp == -1)?(1):((ParamSizeByType[temp2]>0)?(ParamSizeByType[temp2]):(1));
// Get the parameter real special option value
if (temp == 1) temp = ((int) GetIntFromString(&ib)) + 1;
proc->Params[ParamIndex].Option = temp;
proc->Params[ParamIndex].Value = 0;
proc->Params[ParamIndex].Input = IOT_NONE;
proc->Params[ParamIndex].Output = IOT_NONE;
}
// Param source/dest changed?
if (temp4 != 0)
{
if (temp3 == 0)
{
// it may contain previous inline input
if (!((proc->Params[ParamIndex].Input > -1) && (proc->Params[ParamIndex].Input <= __INST_LAST)))
GlobalFree((HANDLE) proc->Params[ParamIndex].Input);
proc->Params[ParamIndex].Input = temp4;
}
if (temp3 == 1)
proc->Params[ParamIndex].Output = temp4;
// Next parameter is output or something else
temp3++;
}
ChangesDone = PCD_DONE;
break;
// Options sections parser
case PST_OPTIONS:
temp2 = 0;
switch (*ib)
{
case ' ':
break;
case '!': temp = -temp; break;
case 'c':
temp2 = POPT_CDECL;
break;
case 'r':
temp2 = POPT_ALWRETURN;
break;
case 'n':
temp2 = POPT_NEVERREDEF;
break;
case 's':
temp2 = POPT_GENSTACK;
break;
case 'e':
temp2 = POPT_ERROR;
break;
case 'u':
temp2 = POPT_UNLOAD;
break;
}
// New Options
if (temp2 != 0)
{
if (temp == 1) proc->Options |= temp2;
else proc->Options &= ~temp2;
// Back to default (turn on nothing) state
temp = 1; temp2 = 0;
}
ChangesDone = PCD_DONE;
break;
}
// Nothing done, just copy char to buffer
if (ChangesDone == PCD_NONE) *(cb++) = *(ib);
// Something done, buffer = ""
else cb = cbuf;
// Increase input pointer
ib++;
}
GlobalFree(ibuf);
GlobalFree(cbuf);
GlobalFree(sbuf);
// Ok, the final step: check proc for existance
if (proc->Proc == NULL)
{
switch (proc->ProcType)
{
case PT_NOTHING: break;
case PT_VTABLEPROC:
{
// Use direct system proc address
int addr;
if ((proc->Dll = addr = (HANDLE) myatoi(proc->DllName)) == 0)
{
proc->ProcResult = PR_ERROR;
break;
}
// fake-real parameter: for COM interfaces first param is Interface Pointer
proc->Params[1].Output = IOT_NONE;
proc->Params[1].Input = AllocStr(proc->DllName);
proc->Params[1].Size = 1;
proc->Params[1].Type = PAT_INT;
proc->Params[1].Option = 0;
// addr - pointer to interface vtable
addr = *((int *)addr);
// now addr contains the pointer to first item at VTABLE
// add the index of proc
addr = addr + (myatoi(proc->ProcName)*4);
proc->Proc = *((HANDLE*)addr);
}
break;
case PT_PROC:
if (*proc->DllName == 0)
{
// Use direct system proc address
if ((proc->Proc = (HANDLE) myatoi(proc->ProcName)) == 0)
proc->ProcResult = PR_ERROR;
} else
{
// Get DLL address
if ((proc->Dll = GetModuleHandle(proc->DllName)) == NULL)
if ((proc->Dll = LoadLibrary(proc->DllName)) == NULL)
{
proc->ProcResult = PR_ERROR;
break;
}
// Get proc address
if ((proc->Proc = GetProcAddress(proc->Dll, proc->ProcName)) == NULL)
{
// automatic A discover
lstrcat(proc->ProcName, "A");
if ((proc->Proc = GetProcAddress(proc->Dll, proc->ProcName)) == NULL)
proc->ProcResult = PR_ERROR;
}
}
break;
case PT_STRUCT:
if (*(proc->ProcName) != 0) proc->Proc = (HANDLE) myatoi(proc->ProcName);
break;
}
}
return proc;
}
void ParamAllocate(SystemProc *proc)
{
int i;
for (i = 0; i <= proc->ParamCount; i++)
if (((HANDLE) proc->Params[i].Value == NULL) && (proc->Params[i].Option == -1))
{
proc->Params[i].Value = (int) GlobalAlloc(GPTR, ParamSizeByType[proc->Params[i].Type]);
}
}
void ParamsIn(SystemProc *proc)
{
int i, *place;
char *realbuf;
LPWSTR wstr;
i = (proc->ParamCount > 0)?(1):(0);
while (TRUE)
{
// Step 1: retrive value
if ((proc->Params[i].Input == IOT_NONE) || (proc->Params[i].Input == IOT_INLINE))
realbuf = AllocStr("");
else if (proc->Params[i].Input == IOT_STACK) realbuf = popstring();
else if ((proc->Params[i].Input > 0) && (proc->Params[i].Input <= __INST_LAST))
realbuf = getuservariable(proc->Params[i].Input - 1);
else
{
// Inline input, will be freed as realbuf
realbuf = (char*) proc->Params[i].Input;
proc->Params[i].Input = IOT_INLINE;
}
// Retreive pointer to place
if (proc->Params[i].Option == -1) place = (int*) proc->Params[i].Value;
else place = (int*) &(proc->Params[i].Value);
// by default no blocks are allocated
proc->Params[i].allocatedBlock = NULL;
// Step 2: place it
switch (proc->Params[i].Type)
{
case PAT_VOID:
proc->Params[i].Value = 0;
break;
case PAT_INT:
*((int*) place) = (int) myatoi(realbuf);
break;
case PAT_LONG:
*((__int64*) place) = myatoi(realbuf);
break;
case PAT_STRING:
/* if (proc->Params[i].Input == IOT_NONE)
*((int*) place) = (int) NULL;
else*/
*((int*) place) = (int) (proc->Params[i].allocatedBlock = AllocStr(realbuf));
break;
case PAT_WSTRING:
case PAT_GUID:
wstr = (LPWSTR) (proc->Params[i].allocatedBlock = GlobalAlloc(GPTR, g_stringsize*2));
MultiByteToWideChar(CP_ACP, 0, realbuf, g_stringsize, wstr, g_stringsize);
if (proc->Params[i].Type == PAT_GUID)
{
*((HGLOBAL*)place) = (proc->Params[i].allocatedBlock = GlobalAlloc(GPTR, 16));
CLSIDFromString(wstr, *((LPCLSID*)place));
GlobalFree((HGLOBAL) wstr);
} else
*((LPWSTR*)place) = wstr;
break;
case PAT_CALLBACK:
// Generate new or use old callback
if (lstrlen(realbuf) > 0)
proc->Params[i].Value = (int) CreateCallback((SystemProc*) myatoi(realbuf));
break;
}
GlobalFree(realbuf);
#ifdef SYSTEM_LOG_DEBUG
{
char buf[1024];
wsprintf(buf, "\t\t\tParam In %d: type %d value 0x%08X value2 0x%08X\n", i,
proc->Params[i].Type, proc->Params[i].Value, proc->Params[i]._value);
SYSTEM_LOG_ADD(buf);
}
#endif
if (i == 0) break;
if (i == proc->ParamCount) i = 0;
else i++;
}
}
void ParamsDeAllocate(SystemProc *proc)
{
int i;
for (i = proc->ParamCount; i >= 0; i--)
if (((HANDLE) proc->Params[i].Value != NULL) && (proc->Params[i].Option == -1))
{
#ifndef _DEBUG
// I see no point for error debug version gives here
GlobalFree((HANDLE) (proc->Params[i].Value));
#endif
proc->Params[i].Value = (int) NULL;
}
}
void ParamsOut(SystemProc *proc)
{
int i, *place;
char *realbuf;
LPWSTR wstr;
i = proc->ParamCount;
do
{
// Retreive pointer to place
if (proc->Params[i].Option == -1) place = (int*) proc->Params[i].Value;
else place = (int*) &(proc->Params[i].Value);
realbuf = AllocString();
// Step 1: retrive value
switch (proc->Params[i].Type)
{
case PAT_VOID:
lstrcpy(realbuf,"");
break;
case PAT_INT:
wsprintf(realbuf, "%d", *((int*) place));
break;
case PAT_LONG:
myitoa64(*((__int64*) place), realbuf);
break;
case PAT_STRING:
{
int num = lstrlen(*((char**) place));
if (num >= g_stringsize) num = g_stringsize-1;
lstrcpyn(realbuf,*((char**) place), num+1);
realbuf[num] = 0;
}
break;
case PAT_GUID:
wstr = (LPWSTR) GlobalAlloc(GPTR, g_stringsize*2);
StringFromGUID2(*((REFGUID*)place), wstr, g_stringsize*2);
WideCharToMultiByte(CP_ACP, 0, wstr, g_stringsize, realbuf, g_stringsize, NULL, NULL);
GlobalFree((HGLOBAL)wstr);
break;
case PAT_WSTRING:
wstr = *((LPWSTR*)place);
WideCharToMultiByte(CP_ACP, 0, wstr, g_stringsize, realbuf, g_stringsize, NULL, NULL);
break;
case PAT_CALLBACK:
wsprintf(realbuf, "%d", proc->Params[i].Value);
break;
}
// memory cleanup
if ((proc->Params[i].allocatedBlock != NULL) && ((proc->ProcType != PT_STRUCT)
|| (proc->Params[i].Option > 0)))
GlobalFree(proc->Params[i].allocatedBlock);
// Step 2: place it
if (proc->Params[i].Output == IOT_NONE);
else if (proc->Params[i].Output == IOT_STACK) pushstring(realbuf);
else if (proc->Params[i].Output > 0) setuservariable(proc->Params[i].Output - 1, realbuf);
GlobalFree(realbuf);
i--;
}
while (i >= 0);
}
void _alloca_probe();
SystemProc __declspec(naked) *CallProc(SystemProc *proc)
{
int z3;
_asm
{
// Save stack
push ebp
mov ebp, esp
// Stack space for local variables
sub esp, __LOCAL_SIZE
// Save all usable registers to free our hands
push ebx
push edi
push esi
}
SYSTEM_LOG_ADD("\t\tCall:\n");
SYSTEM_EVENT("\t\t\tBefore call ")
if (CallbackIndex && (!(proc->Options & POPT_GENSTACK)))
{
_asm
{
push ebp
// Save previous stack location
mov LastStackReal, esp
}
if (LastStackPlace == 0)
{
_asm
{
// Create new stack
mov eax, NEW_STACK_SIZE
call _alloca_probe
mov LastStackPlace, esp
}
} else
_asm
{
// Move stack pointer
mov esp, LastStackPlace
}
}
// Push arguments to stack
for (z1 = proc->ParamCount; z1 > 0; z1--)
{
// Long types
if (proc->Params[z1].Size == 2)
{
z2 = proc->Params[z1]._value;
_asm push z2;
}
// Default
z2 = proc->Params[z1].Value;
_asm push z2;
}
// Call the proc and save return
z1 = (int) proc->Proc;
// Save proc
proc->Clone = LastProc;
_asm
{
mov eax, proc
mov LastProc, eax
}
//LastProc = proc;
SYSTEM_EVENT("\n\t\t\tNear call ")
SYSTEM_LOG_POST;
_asm
{
// Call
call z1
// Return
mov z1, eax
mov z2, edx
}
SYSTEM_LOG_ADD("Back from ");
SYSTEM_LOG_ADD(LastProc->ProcName);
SYSTEM_EVENT("\n\t\t\tShort-After call ")
if ((CallbackIndex) && (!(LastProc->Options & POPT_GENSTACK)))
{
_asm
{
// Restore real stack location
mov LastStackPlace, esp
mov esp, LastStackReal
pop ebp
}
}
// Restore proc
_asm
{
mov eax, LastProc
mov proc, eax
}
// proc = LastProc;
LastProc = proc->Clone;
// In case of cdecl convention we should clear stack
if ((proc->Options & POPT_CDECL) != 0)
{
if ((CallbackIndex > 0) && ((proc->Options & POPT_GENSTACK) == 0))
{
// In case of temporary stack
for (z3 = 1; z3 <= proc->ParamCount; z3++)
LastStackPlace += 4*proc->Params[z3].Size;
} else
{
// in case of real stack
for (z3 = 1; z3 <= proc->ParamCount; z3++)
{
if (proc->Params[z3].Size == 2)
_asm pop edx;
_asm pop edx;
}
}
}
// In case of cleared call-proc-queue -> clear allocated stack place (more flexible)
if (LastProc == NULL) LastStackPlace = (int) NULL;
// Save return
proc->Params[0].Value = z1;
if (proc->Params[0].Size == 2)
proc->Params[0]._value = z2;
// Proc result: OK
proc->ProcResult = PR_OK;
// In case of POPT_ERROR -> GetLastError
if ((proc->Options & POPT_ERROR) != 0)
{
LastError = GetLastError();
}
SYSTEM_EVENT("\n\t\t\tAfter call ")
#ifdef SYSTEM_LOG_DEBUG
{
char buf[1024];
wsprintf(buf, "\n\t\t\tReturn 0x%08X 0x%08X", z1, z2);
SYSTEM_LOG_ADD(buf);
}
#endif
SYSTEM_LOG_POST;
_asm
{
// Return
mov eax, proc
// Restore registers
pop esi
pop edi
pop ebx
// Restore stack pointer
mov esp, ebp
pop ebp
// Return
ret
}
}
SystemProc __declspec(naked) *RealCallBack()
{
SystemProc *proc;
_asm
{
// Save stack
push ebp
mov ebp, esp
// Stack space for local variables
sub esp, __LOCAL_SIZE
// Save all usable registers to free our hands
push ebx
push edi
push esi
// Arguments pointer
mov z2, esp // 1-st arg - 4*4 (pushes) - 4 (return) - __LOCAL_SIZE
add z2, __LOCAL_SIZE
add z2, 5*4
// Our callback proc
mov proc, eax
}
SYSTEM_LOG_ADD("Called callback from ");
SYSTEM_LOG_ADD(LastProc->ProcName);
SYSTEM_EVENT("\n\t\t\tShort-After call ")
SYSTEM_LOG_POST;
// Find last unused clone
while ((proc->Clone != NULL)) proc = proc->Clone;
// 2. Create new clone
proc = (proc->Clone = GlobalCopy(proc));
// 3. Set clone option
proc->Options |= POPT_CLONE;
// Read arguments
proc->ArgsSize = 0;
for (z1 = 1; z1 <= proc->ParamCount; z1++)
{
// Default
proc->Params[z1].Value = *(((int*)z2)++);
proc->ArgsSize += 4;
// Long only
if (proc->Params[z1].Size == 2)
{
proc->Params[z1]._value = *(((int*)z2)++);
proc->ArgsSize += 4;
}
}
proc->ProcResult = PR_CALLBACK;
_asm
{
// Return
mov eax, proc
// Save temporary stack info
push ebp
// push LastStackPlace
mov LastStackPlace, esp
// Restore real stack
mov esp, LastStackReal
pop ebp
// pop LastStackReal
}
_asm
{
// Fake return from System::Call
// Restore registers
pop esi
pop edi
pop ebx
// Restore stack pointer
mov esp, ebp
pop ebp
// Return
ret
}
}
SystemProc __declspec(naked) *CallBack(SystemProc *proc)
{
_asm
{
// Save stack
push ebp
mov ebp, esp
// Stack space for local variables
sub esp, __LOCAL_SIZE
// Save all usable registers to free our hands
push ebx
push edi
push esi
}
// MessageBox(NULL, "cool1", "Cool", MB_OK);
SYSTEM_LOG_ADD("\t\tReturn from callback:\n");
SYSTEM_EVENT("\t\t\tBefore call-back ");
SYSTEM_LOG_POST;
//z1 = proc->Params[0].Value;
//z2 = proc->Params[0]._value;
//z1 = &(proc->Params[0].Value);
_asm
{
mov eax, proc
add eax, SYSTEM_ZERO_PARAM_VALUE_OFFSET
push [eax]
push [eax+4]
}
// Adjust return statement
if ((proc->Options & POPT_CDECL) == 0) retexpr[1] = proc->ArgsSize;
else retexpr[1] = 0x0;
// Right return statement address
retaddr = (HANDLE) retexpr;
// Remove unneeded callback proc
GlobalFree((HANDLE) proc);
// MessageBox(NULL, "cool2", "Cool", MB_OK);
_asm
{
// Prepare return
// mov eax, z1
//mov edx, z2
// Restore temporary stack and return
// Save real stack info
// Save previous stack location
// push LastStackReal
push ebp
mov LastStackReal, esp
// Move stack pointer
mov esp, LastStackPlace
// pop LastStackPlace
pop ebp
}
#ifdef SYSTEM_LOG_DEBUG
SYSTEM_EVENT("\n\t\t\tSh-Before call-back");
SYSTEM_LOG_POST;
#endif
// Fake return from Callback
_asm {
// callback proc result
pop edx
pop eax
// Restore registers
pop esi
pop edi
pop ebx
// Restore stack pointer
mov esp, ebp
pop ebp
// Return
jmp retaddr
}
}
HANDLE CreateCallback(SystemProc *cbproc)
{
char *mem;
if (cbproc->Proc == NULL)
{
// Set callback index
cbproc->CallbackIndex = ++(CallbackIndex);
cbproc->Options |= POPT_PERMANENT;
mem = (char *) (cbproc->Proc = GlobalAlloc(GPTR, 10));
*(mem++) = 0xB8; // Mov eax, const
*(((int *)mem)++) = (int) cbproc;
*(mem++) = 0xe9; // Jmp relative
*((int *)mem) = (int) RealCallBack;
*((int *)mem) -= ((int) mem) + 4;
}
// Return proc address
return cbproc->Proc;
}
void CallStruct(SystemProc *proc)
{
BOOL ssflag;
int i, structsize = 0, size = 0;
char *st, *ptr;
SYSTEM_LOG_ADD("\t\tStruct...");
// Calculate the structure size
for (i = 1; i <= proc->ParamCount; i++)
if (proc->Params[i].Option < 1)
structsize += proc->Params[i].Size * 4;
else
structsize += proc->Params[i].Option-1;
// Struct exists?
if (proc->Proc == NULL)
// No. Allocate struct memory
proc->Proc = (HANDLE) GlobalAlloc(GPTR, structsize);
else // In case of zero size defined structure use mapped size
if (structsize == 0) structsize = (int) GlobalSize((HANDLE) proc->Proc);
// Pointer to current data
st = (char*) proc->Proc;
for (i = 1; i <= proc->ParamCount; i++)
{
ssflag = FALSE;
// Normal or special block?
if (proc->Params[i].Option < 1)
{
// Normal
size = proc->Params[i].Size*4;
ptr = (char*) &(proc->Params[i].Value);
}
else
{
int intmask[4] = {0xFFFFFFFF, 0x000000FF, 0x0000FFFF, 0x00FFFFFF};
// Special
size = proc->Params[i].Option-1;
switch (proc->Params[i].Type)
{
case PAT_VOID: ptr = NULL; break;
case PAT_LONG:
// real structure size
proc->Params[i].Value = structsize;
proc->Params[i]._value = 0;
ssflag = TRUE;
case PAT_INT:
// clear unused value bits
proc->Params[i].Value &= intmask[((size >= 0) && (size < 4))?(size):(0)];
// pointer
ptr = (char*) &(proc->Params[i].Value);
break;
case PAT_STRING:
case PAT_GUID:
case PAT_WSTRING:
ptr = (char*) proc->Params[i].Value; break;
}
}
// Process them!
if (ptr != NULL)
{
// Input
if ((proc->Params[i].Input != IOT_NONE) || (ssflag))
copymem(st, ptr, size);
// Output
if (proc->Params[i].Output != IOT_NONE)
copymem(ptr, st, size);
}
// Skip to next data block
st += size;
}
SYSTEM_LOG_POST;
// Proc virtual return - pointer to memory struct
proc->Params[0].Value = (int) proc->Proc;
}
BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
g_hInstance=hInst;
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
// initialize some variables
LastStackPlace = 0;
LastStackReal = 0;
LastError = 0;
LastProc = NULL;
CallbackIndex = 0;
retexpr[0] = 0xC2;
retexpr[2] = 0x00;
}
return TRUE;
}