Last active
December 24, 2015 21:39
-
-
Save oscar-broman/6866913 to your computer and use it in GitHub Desktop.
db_query error reporting
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <a_samp> | |
#tryinclude "amx_assembly\amx_header" | |
#if !defined _inc_amx_header | |
#error amx_assembly is required. Get it here: github.com/zeex/amx_assembly | |
#endif | |
#include "amx_assembly\dynamic_call" | |
#include "amx_assembly\phys_memory" | |
#include "amx_assembly\windows\import_table" | |
#include "amx_assembly\shellcode" | |
#include "amx_assembly\os" | |
static stock const PAGE_NOACCESS = 0x01; | |
static stock const PAGE_READONLY = 0x02; | |
static stock const PAGE_READWRITE = 0x04; | |
static stock const PAGE_WRITECOPY = 0x08; | |
static stock const PAGE_EXECUTE = 0x10; | |
static stock const PAGE_EXECUTE_READ = 0x20; | |
static stock const PAGE_EXECUTE_READWRITE = 0x40; | |
static stock const PAGE_EXECUTE_WRITECOPY = 0x80; | |
static stock const PAGE_GUARD = 0x100; | |
static stock const PAGE_NOCACHE = 0x200; | |
static stock const PAGE_WRITECOMBINE = 0x400; | |
static stock s_LastError[512]; | |
forward OnSQLiteQueryError(error[]); | |
// phys_memory.inc | |
static stock AbsToRel(addr) { | |
new dat; | |
#emit lctrl 1 | |
#emit stor.s.pri dat | |
return addr - (GetAmxBaseAddress() + dat); | |
} | |
// This function has a bug in older amx_assembly versions | |
static stock WritePhysMemoryCell_(addr, what) { | |
new rel_addr = AbsToRel(addr); | |
#emit load.s.pri what | |
#emit sref.s.pri rel_addr | |
#emit stack 4 | |
#emit retn | |
return 0; // make compiler happy | |
} | |
// https://github.com/Zeex/amx_assembly/blob/master/windows/ShellExecute.inc | |
static stock VirtualProtect(addr, size, new_protect, &old_protect = 0) { | |
/* | |
.text:10001000 55 push ebp | |
.text:10001001 8B EC mov ebp, esp | |
.text:10001011 8B 4D 0C mov ecx, [ebp+arg_4] | |
.text:10001014 8B 51 10 mov edx, [ecx+10h] | |
.text:10001017 52 push edx ; lpflOldProtect | |
.text:10001018 8B 45 0C mov eax, [ebp+arg_4] | |
.text:1000101B 8B 48 0C mov ecx, [eax+0Ch] | |
.text:1000101E 51 push ecx ; flNewProtect | |
.text:1000101F 8B 55 0C mov edx, [ebp+arg_4] | |
.text:10001022 8B 42 08 mov eax, [edx+8] | |
.text:10001025 50 push eax ; dwSize | |
.text:10001026 8B 4D 0C mov ecx, [ebp+arg_4] | |
.text:10001029 8B 51 04 mov edx, [ecx+4] | |
.text:1000102C 52 push edx ; lpAddress | |
.text:1000102D FF 15 78 56 34 12 call ds:VirtualProtect | |
.text:10001033 5D pop ebp | |
.text:10001034 C3 retn | |
*/ | |
#define __(%0,%1,%2,%3) (((0x%3) << 24) | ((0x%2) << 16) | (0x%1 << 8) | (0x%0)) | |
static const asm[] = { | |
__(90,90,90,90), | |
__(90,90,90,90), | |
__(90,90,90,90), | |
__(90,90,90,90), | |
__(55,8B,EC,90), | |
__(90,8B,4D,0C), | |
__(8B,51,10,52), | |
__(8B,45,0C,8B), | |
__(48,0C,51,8B), | |
__(55,0C,8B,42), | |
__(08,50,8B,4D), | |
__(0C,8B,51,04), | |
__(52,FF,15,00), | |
__(00,00,00,5D), | |
__(C3,CC,CC,CC) | |
}; | |
#undef __ | |
static address = -1; | |
if (address == -1) { | |
address = GetImportAddress("VirtualProtect"); | |
WriteAmxMemory(ref(asm) + 51, refabs(address)); | |
} | |
Push(addr); // LPVOID lpAddress | |
Push(size); // SIZE_T dwSize | |
Push(new_protect); // DWORD flNewProtect | |
Push(refabs(old_protect)); // PDWORD lpflOldProtect | |
return RunShellcode(refabs(asm)); | |
} | |
static stock patch_db_query() { | |
if (!IsWindows()) { | |
return false; | |
} | |
new addr = GetNativeAddressFromName("db_query"); | |
if (!addr) { | |
printf("Unable to patch db_query: unable to get the address of db_query."); | |
return false; | |
} | |
// addr+144: | |
// JE SHORT 0044DCB7 -> JMP SHORT 0044DCB7 | |
addr += 144; | |
new opcodes = ReadPhysMemoryCell(addr); | |
if (opcodes != 0xE8561574) { | |
printf("Unable to patch db_query: unexpected opcodes."); | |
return false; | |
} | |
new old_protect; | |
// Make it possible to write to "addr" | |
VirtualProtect(addr, 4, PAGE_EXECUTE_READWRITE, old_protect); | |
// change JE to JMP | |
WritePhysMemoryCell_(addr, 0xEB | (ReadPhysMemoryCell(addr) & 0xFFFFFF00)); | |
// Put the VirtualProtect back to what it was | |
VirtualProtect(addr, 4, old_protect); | |
return true; | |
} | |
static stock db_get_error(DBResult:r, output[], maxlength = sizeof(output)) { | |
if (!r) { | |
output[0] = '\0'; | |
return false; | |
} | |
// the error message is a char* in dbresult+12 | |
new errptr = ReadPhysMemoryCell(_:r + 12); | |
if (errptr) { | |
new i = -1; | |
// read C string | |
do { | |
if (i >= maxlength - 1) { | |
output[maxlength - 1] = '\0'; | |
break; | |
} | |
output[++i] = ReadPhysMemoryCell(errptr + i * 4); | |
output[i] = swapchars(output[i]); | |
} while (strlen(output[i]) == 4); | |
strunpack(output, output, maxlength); | |
return true; | |
} | |
output[0] = '\0'; | |
return false; | |
} | |
stock DBResult:ERR_db_query(DB:db, query[]) { | |
static has_patched = false; | |
if (!has_patched) { | |
patch_db_query(); | |
has_patched = true; | |
} | |
new DBResult:r = db_query(db, query); | |
if (db_get_error(r, s_LastError)) { | |
db_free_result(r); | |
#if defined THE_OnSQLiteQueryError | |
THE_OnSQLiteQueryError(s_LastError); | |
#else | |
printf("(db_query) Error: %s", s_LastError); | |
#endif | |
return DBResult:0; | |
} | |
return r; | |
} | |
#define OnSQLiteQueryError THE_OnSQLiteQueryError | |
stock db_get_last_error() { | |
return s_LastError; | |
} | |
#if defined _ALS_db_query | |
#undef db_query | |
#else | |
native OLD_db_query(DB:db, query[]) = db_query; | |
#define _ALS_db_query | |
#endif | |
#define db_query ERR_db_query |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment