Skip to content

Instantly share code, notes, and snippets.

@oscar-broman
Last active December 24, 2015 21:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oscar-broman/6866913 to your computer and use it in GitHub Desktop.
Save oscar-broman/6866913 to your computer and use it in GitHub Desktop.
db_query error reporting
#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