BOOL CNktStringW::Concat(__in double nSrc, __in int nDigits) { WCHAR szTempW[128], szFmtW[16]; if (nDigits < 0) nDigits = 0; if (nDigits > 15) nDigits = 15; swprintf_s(szFmtW, X_ARRAYLEN(szFmtW), L"%%.%ldf", (long)nDigits); swprintf_s(szTempW, X_ARRAYLEN(szTempW), szFmtW, nSrc); return Concat(szTempW); }
BOOL CNktStringW::AppendFormatV(__in LPCSTR szFormatA, __in va_list argptr) { CHAR szTempBufA[512], *szTempA; int nChars; BOOL b; if (szFormatA == NULL) return FALSE; nChars = _vscprintf(szFormatA, argptr); if (nChars > 0) { if (nChars+1 >= X_ARRAYLEN(szTempBufA)) { szTempA = (LPSTR)NKT_MALLOC((size_t)(nChars+1) * sizeof(CHAR)); if (szTempA == NULL) return FALSE; } else { szTempA = szTempBufA; } vsprintf_s(szTempA, (size_t)nChars+1, szFormatA, argptr); b = ConcatN(szTempA, (size_t)nChars); if (szTempA != szTempBufA) { NKT_FREE(szTempA); } if (b == FALSE) return FALSE; } return TRUE; }
BOOL CNktStringW::Concat(__in ULONGLONG nSrc) { WCHAR szTempW[128]; swprintf_s(szTempW, X_ARRAYLEN(szTempW), L"%I64u", nSrc); return Concat(szTempW); }
static HRESULT ProcessVariable(__in FILE *fp, __in WORD nIndex, __in TYPEATTR* lpTypeAttr, __in ITypeInfo *lpTypeInfo, __in SIZE_T nIndent) { CAutoVarDesc cVarDesc; CNktStringW cStrTempW; CNktComBStr bstrMemberName; BSTR bstr; HRESULT hRes; UINT nNamesCount; WORD i; char szBufA[32]; hRes = cVarDesc.Set(lpTypeInfo, nIndex); EXIT_ON_ERROR(hRes); if (cVarDesc->varkind == VAR_CONST) { _tprintf_s(_T("Error: Variables should not be constants.\n")); return E_NOTIMPL; } hRes = lpTypeInfo->GetNames(cVarDesc->memid, &bstr, 1, &nNamesCount); EXIT_ON_ERROR(hRes); if (nNamesCount == 0 || bstr == NULL) { _tprintf_s(_T("Error: Unnamed variables are not supported.\n")); return E_NOTIMPL; } bstrMemberName.Attach(bstr); WRITEINDENT_AND_CHECK(fp, nIndent); if ((cVarDesc->elemdescVar.tdesc.vt & 0x0FFF) == VT_CARRAY) { // type name[n] cStrTempW.Empty(); hRes = TypeDescToString(cStrTempW, &(cVarDesc->elemdescVar.tdesc.lpadesc->tdescElem), lpTypeInfo, FALSE); EXIT_ON_ERROR(hRes); WRITEWIDE_AND_CHECK(fp, (LPWSTR)cStrTempW); WRITEANSI_AND_CHECK(fp, " "); WRITEBSTR_AND_CHECK(fp, bstrMemberName); for (i=0; i<cVarDesc->elemdescVar.tdesc.lpadesc->cDims; i++) { _snprintf_s(szBufA, X_ARRAYLEN(szBufA), _TRUNCATE, "[%d]", cVarDesc->elemdescVar.tdesc.lpadesc->rgbounds[i].cElements); WRITEANSI_AND_CHECK(fp, szBufA); } } else { cStrTempW.Empty(); hRes = TypeDescToString(cStrTempW, &(cVarDesc->elemdescVar.tdesc), lpTypeInfo, FALSE); EXIT_ON_ERROR(hRes); WRITEWIDE_AND_CHECK(fp, (LPWSTR)cStrTempW); WRITEANSI_AND_CHECK(fp, " "); WRITEBSTR_AND_CHECK(fp, bstrMemberName); } WRITEANSI_AND_CHECK(fp, ";\r\n"); return S_OK; }
static HRESULT GetTypeLibVersion(__in REFGUID rGuid, __out WORD &wVerMajor, __out WORD &wVerMinor) { TCHAR szBuf[256], *sT; LONG lRes; DWORD dwIndex; WORD wMj, wMi; HKEY hTypeLibKey; wVerMajor = wVerMinor = 0; _sntprintf_s(szBuf, X_ARRAYLEN(szBuf), _TRUNCATE, _T("TypeLib\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}"), rGuid.Data1, rGuid.Data2, rGuid.Data3, rGuid.Data4[0], rGuid.Data4[1], rGuid.Data4[2], rGuid.Data4[3], rGuid.Data4[4], rGuid.Data4[5], rGuid.Data4[6], rGuid.Data4[7]); lRes = ::RegOpenKeyEx(HKEY_CLASSES_ROOT, szBuf, 0, KEY_READ, &hTypeLibKey); if (lRes != ERROR_SUCCESS) { if (lRes == ERROR_NOT_FOUND || lRes == ERROR_FILE_NOT_FOUND || lRes == ERROR_PATH_NOT_FOUND) return TYPE_E_LIBNOTREGISTERED; return HRESULT_FROM_WIN32(lRes); } for (dwIndex=0; ::RegEnumKey(hTypeLibKey, dwIndex, szBuf, X_ARRAYLEN(szBuf))==ERROR_SUCCESS; dwIndex++) { wMj = (WORD)_ttoi(szBuf); sT = _tcsrchr(szBuf, _T('.')); wMi = (sT != NULL) ? (WORD)_ttoi(sT+1) : 0; if (wMj > wVerMajor || (wMj == wVerMajor && wMi > wVerMinor)) { wVerMajor = wMj; wVerMinor = wMi; } } ::RegCloseKey(hTypeLibKey); return (wVerMajor != 0) ? S_OK : TYPE_E_LIBNOTREGISTERED; }
static HRESULT ProcessHeader(__in FILE *fp, __in ITypeLib *lpTypeLib) { TLIBATTR *lpLibAttr; CHAR szBufA[256]; CNktComBStr bstrName, bstrDoc; LPWSTR sW; GUID sLibGuid; HRESULT hRes; WRITEANSI_AND_CHECK(fp, "// Generated .H file using Deviare's TLB-to-Header application\r\n"); WRITEANSI_AND_CHECK(fp, "//------------------------------------------------------------\r\n"); hRes = lpTypeLib->GetLibAttr(&lpLibAttr); EXIT_ON_ERROR(hRes); memcpy(&sLibGuid, &(lpLibAttr->guid), sizeof(sLibGuid)); lpTypeLib->ReleaseTLibAttr(lpLibAttr); //---- hRes = lpTypeLib->GetDocumentation(MEMBERID_NIL, &bstrName, &bstrDoc, 0, 0); EXIT_ON_ERROR(hRes); //---- sW = (LPWSTR)(BSTR)bstrDoc; if (sW == NULL || sW[0] == 0) sW = (LPWSTR)(BSTR)bstrName; if (sW != NULL && sW[0] != 0) { WRITEANSI_AND_CHECK(fp, "// Name: "); WRITEWIDE_AND_CHECK(fp, sW); WRITEANSI_AND_CHECK(fp, "\r\n"); } WRITEANSI_AND_CHECK(fp, "// Guid: "); _snprintf_s(szBufA, X_ARRAYLEN(szBufA), _TRUNCATE, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", sLibGuid.Data1, sLibGuid.Data2, sLibGuid.Data3, sLibGuid.Data4[0], sLibGuid.Data4[1], sLibGuid.Data4[2], sLibGuid.Data4[3], sLibGuid.Data4[4], sLibGuid.Data4[5], sLibGuid.Data4[6], sLibGuid.Data4[7]); WRITEANSI_AND_CHECK(fp, szBufA); WRITEANSI_AND_CHECK(fp, "\r\n"); //done return S_OK; }
HRESULT CXmlHelper::Initialize(IXMLDOMElement *lpRootElem) { TNktComPtr<IXMLDOMElement> cCurrElem, cNextElem; CNktComBStr cElemAttrIdBStr, cNameBstr; HRESULT hRes; SIZE_T i; LONG k; nktMemSet(aFundTypesIndexes, 0, sizeof(aFundTypesIndexes)); hRes = GetFirstChildElement(lpRootElem, &cCurrElem); if (FAILED(hRes)) return hRes; while (cCurrElem != NULL) { cElemAttrIdBStr.Reset(); hRes = GetAttributeValue(cCurrElem, L"id", &cElemAttrIdBStr); if (FAILED(hRes)) { init_on_error: Reset(); return hRes; } if (cElemAttrIdBStr[0] != 0) { //add this element if (nIdElemMapEntriesCount >= nIdElemMapEntriesSize) { ID_ELEM_MAP_ENTRY *lpNew; lpNew = (ID_ELEM_MAP_ENTRY*)nktMemMalloc((nIdElemMapEntriesSize+10240)*sizeof(ID_ELEM_MAP_ENTRY)); if (lpNew == NULL) { hRes = E_OUTOFMEMORY; goto init_on_error; } nIdElemMapEntriesSize += 10240; if (lpIdElemMapEntries != NULL) { nktMemCopy(lpNew, lpIdElemMapEntries, nIdElemMapEntriesCount*sizeof(ID_ELEM_MAP_ENTRY)); nktMemFree(lpIdElemMapEntries); } lpIdElemMapEntries = lpNew; } wcsncpy_s(lpIdElemMapEntries[nIdElemMapEntriesCount].szIdW, cElemAttrIdBStr, 16); lpIdElemMapEntries[nIdElemMapEntriesCount].szIdW[15] = 0; k = GetDbObjectClass(cCurrElem, 1); if (k == -1) { hRes = E_OUTOFMEMORY; goto init_on_error; } if (k == NKT_DBOBJCLASS_Fundamental) { cNameBstr.Reset(); hRes = GetAttributeValue(cCurrElem, L"name", &cNameBstr); if (FAILED(hRes)) goto init_on_error; if (_wcsicmp((LPWSTR)cNameBstr, L"signed char") == 0) k = NKT_DBFUNDTYPE_SignedByte; else if (_wcsicmp((LPWSTR)cNameBstr, L"char") == 0) k = NKT_DBFUNDTYPE_AnsiChar; else if (_wcsicmp((LPWSTR)cNameBstr, L"unsigned char") == 0) k = NKT_DBFUNDTYPE_UnsignedByte; else if (_wcsicmp((LPWSTR)cNameBstr, L"short int") == 0) k = NKT_DBFUNDTYPE_SignedWord; else if (_wcsicmp((LPWSTR)cNameBstr, L"short unsigned int") == 0) k = NKT_DBFUNDTYPE_UnsignedWord; else if (_wcsicmp((LPWSTR)cNameBstr, L"int") == 0 || _wcsicmp((LPWSTR)cNameBstr, L"long int") == 0 || _wcsicmp((LPWSTR)cNameBstr, L"bool") == 0) k = NKT_DBFUNDTYPE_SignedDoubleWord; else if (_wcsicmp((LPWSTR)cNameBstr, L"unsigned int") == 0 || _wcsicmp((LPWSTR)cNameBstr, L"long unsigned int") == 0) k = NKT_DBFUNDTYPE_UnsignedDoubleWord; else if (_wcsicmp((LPWSTR)cNameBstr, L"long long int") == 0) k = NKT_DBFUNDTYPE_SignedQuadWord; else if (_wcsicmp((LPWSTR)cNameBstr, L"long long unsigned int") == 0) k = NKT_DBFUNDTYPE_UnsignedQuadWord; else if (_wcsicmp((LPWSTR)cNameBstr, L"float") == 0) k = NKT_DBFUNDTYPE_Float; else if (_wcsicmp((LPWSTR)cNameBstr, L"double") == 0) k = NKT_DBFUNDTYPE_Double; else if (_wcsicmp((LPWSTR)cNameBstr, L"long double") == 0) k = NKT_DBFUNDTYPE_LongDouble; else if (_wcsicmp((LPWSTR)cNameBstr, L"wchar_t") == 0) k = NKT_DBFUNDTYPE_WideChar; else if (_wcsicmp((LPWSTR)cNameBstr, L"void") == 0) k = NKT_DBFUNDTYPE_Void; else { hRes = E_FAIL; goto init_on_error; } aFundTypesIndexes[k-NKT_DBFUNDTYPE_MIN] = 1; } else k = 0; lpIdElemMapEntries[nIdElemMapEntriesCount].nFundamentalType = (ULONG)k; lpIdElemMapEntries[nIdElemMapEntriesCount].lpElem = cCurrElem; lpIdElemMapEntries[nIdElemMapEntriesCount].lpElem->AddRef(); nIdElemMapEntriesCount++; } //get next element hRes = GetNextElement(cCurrElem, &cNextElem); if (FAILED(hRes)) goto init_on_error; cCurrElem.Attach(cNextElem.Detach()); } //fast fundamental quick check for (k=0; k<X_ARRAYLEN(aFundTypesIndexes); k++) { if (aFundTypesIndexes[k] == 0) { hRes = E_FAIL; goto init_on_error; } } //sort elements by id qsort_s(lpIdElemMapEntries, nIdElemMapEntriesCount, sizeof(ID_ELEM_MAP_ENTRY), IdElemMapEntry_Compare, NULL); //find each fundamental nktMemSet(aFundTypesIndexes, 0, sizeof(aFundTypesIndexes)); for (i=0; i<nIdElemMapEntriesCount; i++) { if (lpIdElemMapEntries[i].nFundamentalType != 0) aFundTypesIndexes[lpIdElemMapEntries[i].nFundamentalType - NKT_DBFUNDTYPE_MIN] = i; } //fast fundamental quick check (should not happen) for (k=0; k<X_ARRAYLEN(aFundTypesIndexes); k++) { if (aFundTypesIndexes[k] == 0) { hRes = E_FAIL; goto init_on_error; } } return S_OK; }
static HRESULT ProcessFunction(__in FILE *fp, __in WORD nIndex, __in TYPEATTR* lpTypeAttr, __in ITypeInfo *lpTypeInfo, __in SIZE_T nIndent, __in LPWSTR szParentThisW) { CAutoFuncDesc cFuncDesc; CNktStringW cStrTempW; CNktComBStr bstrNames[MAX_FUNCTION_NAMES]; BSTR bstr[MAX_FUNCTION_NAMES]; HRESULT hRes; CNktComVariant vtValue; UINT i, j, nNamesCount; char szBufA[32]; hRes = cFuncDesc.Set(lpTypeInfo, nIndex); EXIT_ON_ERROR(hRes); //Write return type cStrTempW.Empty(); hRes = TypeDescToString(cStrTempW, &(cFuncDesc->elemdescFunc.tdesc), lpTypeInfo, FALSE); EXIT_ON_ERROR(hRes); WRITEINDENT_AND_CHECK(fp, nIndent); WRITEWIDE_AND_CHECK(fp, (LPWSTR)cStrTempW); WRITEANSI_AND_CHECK(fp, " ("); if (lpTypeAttr->typekind != TKIND_DISPATCH) { // Write calling convention switch (cFuncDesc->callconv) { case CC_CDECL: WRITEANSI_AND_CHECK(fp, "_cdecl "); break; case CC_PASCAL: WRITEANSI_AND_CHECK(fp, "__pascal "); break; case CC_STDCALL: WRITEANSI_AND_CHECK(fp, "__stdcall "); break; default: _tprintf_s(_T("Error: Unsupported calling convetion '%04X'.\n"), cFuncDesc->callconv); return E_NOTIMPL; } } else { WRITEANSI_AND_CHECK(fp, "__stdcall "); } WRITEANSI_AND_CHECK(fp, "*"); // Write methodname // // Problem: If a property has the propput or propputref attributes the // 'right hand side' (rhs) is *always* the last parameter and MkTypeLib // strips the parameter name. Thus you will always get 1 less name // back from ::GetNames than normal. // // Thus for the example below // [propput] void Color([in] VARIANT rgb, [in] VARIANT rgb2 ); // without taking this into consderation the output would be // [propput] void Color([in] VARIANT rgb, [in] VARIANT ); // when it should be // [propput] void Color([in] VARIANT rgb, [in] VARIANT rhs ); // // Another weirdness comes from a bug (which will never be fixed) // where optional parameters on property functions were allowed. // Because they were allowed by accident people used them, so they // are still allowed. nNamesCount = 0; hRes = lpTypeInfo->GetNames(cFuncDesc->memid, bstr, MAX_FUNCTION_NAMES, &nNamesCount); EXIT_ON_ERROR(hRes); for (i=0; i<nNamesCount; i++) bstrNames[i].Attach(bstr[i]); // fix for 'rhs' problem if (nNamesCount < (UINT)cFuncDesc->cParams+1) { hRes = bstrNames[nNamesCount++].Set(L"rhs"); EXIT_ON_ERROR(hRes); } NKT_ASSERT(nNamesCount == cFuncDesc->cParams+1); if ((cFuncDesc->invkind & INVOKE_PROPERTYGET) != 0) { WRITEANSI_AND_CHECK(fp, "get_"); } else if ((cFuncDesc->invkind & INVOKE_PROPERTYPUT) != 0) { WRITEANSI_AND_CHECK(fp, "put_"); } else if ((cFuncDesc->invkind & INVOKE_PROPERTYPUTREF) != 0) { WRITEANSI_AND_CHECK(fp, "putref_"); } WRITEBSTR_AND_CHECK(fp, bstrNames[0]); WRITEANSI_AND_CHECK(fp, ")("); if (szParentThisW != NULL) { WRITEWIDE_AND_CHECK(fp, szParentThisW); WRITEANSI_AND_CHECK(fp, "* This"); } // params have the format // [attributes] type paramname // where attributes can be // in, out, optional, string (string is not valid for TKIND_MODULE) for (i=0; i<(UINT)(cFuncDesc->cParams); i++) { if (i > 0 || szParentThisW != NULL) { WRITEANSI_AND_CHECK(fp, ", "); } // type if ((cFuncDesc->lprgelemdescParam[i].tdesc.vt & 0x0FFF) == VT_CARRAY) { // type name[n] cStrTempW.Empty(); hRes = TypeDescToString(cStrTempW, &(cFuncDesc->lprgelemdescParam[i].tdesc.lpadesc->tdescElem), lpTypeInfo, FALSE); EXIT_ON_ERROR(hRes); WRITEWIDE_AND_CHECK(fp, (LPWSTR)cStrTempW); WRITEANSI_AND_CHECK(fp, " "); WRITEBSTR_AND_CHECK(fp, bstrNames[i+1]); for (j=0; j<cFuncDesc->lprgelemdescParam[i].tdesc.lpadesc->cDims; j++) { _snprintf_s(szBufA, X_ARRAYLEN(szBufA), _TRUNCATE, "[%d]", cFuncDesc->lprgelemdescParam[i].tdesc.lpadesc->rgbounds[j].cElements); WRITEANSI_AND_CHECK(fp, szBufA); } } else { cStrTempW.Empty(); hRes = TypeDescToString(cStrTempW, &(cFuncDesc->lprgelemdescParam[i].tdesc), lpTypeInfo, FALSE); EXIT_ON_ERROR(hRes); WRITEWIDE_AND_CHECK(fp, (LPWSTR)cStrTempW); WRITEANSI_AND_CHECK(fp, " "); WRITEBSTR_AND_CHECK(fp, bstrNames[i+1]); } } WRITEANSI_AND_CHECK(fp, ");\r\n"); return S_OK; }
static BOOL WriteString(__in FILE *fp, __in_z LPCWSTR szStringW, __in_opt SIZE_T nLength) { SIZE_T i, j, nStart; WCHAR szTempW[32]; if (szStringW == NULL) return S_OK; if (nLength == NKT_SIZE_T_MAX) nLength = wcslen(szStringW); for (i=0; i<nLength; i++) { nStart = i; for (j=0; j<X_ARRAYLEN(szTempW)-1 && i<nLength; j++) { if (iswprint(szStringW[i]) == 0 || szStringW[i] == L'\"' || szStringW[i] == L'\\') break; szTempW[j] = szStringW[i++]; } if (i > nStart) { szTempW[j] = 0; if (fprintf(fp, "%S", szTempW) == 0) return FALSE; } while (i < nLength) { if (iswprint(szStringW[i]) != 0 && szStringW[i] != L'\"' && szStringW[i] != L'\\') break; switch (szStringW[i]) { case L'\"': if (fprintf(fp, "\\\"") == 0) return FALSE; break; case L'\\': if (fprintf(fp, "\\\\") == 0) return FALSE; break; case L'\a': if (fprintf(fp, "\\a") == 0) return FALSE; break; case L'\b': if (fprintf(fp, "\\b") == 0) return FALSE; break; case L'\f': if (fprintf(fp, "\\f") == 0) return FALSE; break; case L'\n': if (fprintf(fp, "\\n") == 0) return FALSE; break; case L'\r': if (fprintf(fp, "\\r") == 0) return FALSE; break; case L'\t': if (fprintf(fp, "\\t") == 0) return FALSE; break; case L'\v': if (fprintf(fp, "\\v") == 0) return FALSE; break; case L'\0': if (fprintf(fp, "\\0") == 0) return FALSE; break; default: if (fprintf(fp, "\\x%02X", szStringW[i]) == 0) return FALSE; break; } i++; } } return TRUE; }
DWORD CNktHookLib::RemoteHook(__inout HOOK_INFO aHookInfo[], __in SIZE_T nCount, __in DWORD dwPid, __in DWORD dwFlags) { DWORD dwOsErr; if (dwPid == 0) return ERROR_INVALID_PARAMETER; if (lpInternals != NULL) { NktHookLib::CNktAutoFastMutex cAutoLock(&(int_data->cMtx)); NktHookLib::CProcessesHandles::CEntryPtr cProcEntry; NktHookLib::CHookEntry *lpHookEntry, **lpNewEntriesList; BYTE aNewCode[0x80 + HOOKENG_MAX_STUB_SIZE]; SIZE_T nSize, nHookIdx; LPBYTE lpPtr; DWORD dw; NTSTATUS nNtStatus; if (aHookInfo == 0 || nCount == 0) return ERROR_INVALID_PARAMETER; for (nHookIdx=0; nHookIdx<nCount; nHookIdx++) { if (aHookInfo[nHookIdx].lpProcToHook == NULL || aHookInfo[nHookIdx].lpNewProcAddr == NULL) return ERROR_INVALID_PARAMETER; aHookInfo[nHookIdx].nHookId = 0; aHookInfo[nHookIdx].lpCallOriginal = NULL; } //get process handle cProcEntry.Attach(int_data->cProcHdrMgr.Get(dwPid)); if (cProcEntry == NULL) return ERROR_ACCESS_DENIED; //create entries for each item lpNewEntriesList = (NktHookLib::CHookEntry**)NktHookLibHelpers::MemAlloc(nCount*sizeof(NktHookLib::CHookEntry*)); if (lpNewEntriesList != NULL) { dwOsErr = NO_ERROR; NktHookLibHelpers::MemSet(lpNewEntriesList, 0, nCount * sizeof(NktHookLib::CHookEntry*)); } else { dwOsErr = ERROR_NOT_ENOUGH_MEMORY; } for (nHookIdx=0; nHookIdx<nCount && dwOsErr==NO_ERROR; nHookIdx++) { //allocate new entry lpHookEntry = new NktHookLib::CHookEntry(cProcEntry); if (lpHookEntry == NULL) { dwOsErr = ERROR_NOT_ENOUGH_MEMORY; continue; } lpNewEntriesList[nHookIdx] = lpHookEntry; lpHookEntry->lpOrigProc = (LPBYTE)(aHookInfo[nHookIdx].lpProcToHook); if ((dwFlags & NKTHOOKLIB_DontSkipInitialJumps) == 0) { lpHookEntry->lpOrigProc = lpHookEntry->SkipJumpInstructions(lpHookEntry->lpOrigProc); if (lpHookEntry->lpOrigProc == NULL) { dwOsErr = ERROR_ACCESS_DENIED; continue; } } lpHookEntry->lpNewProc = (LPBYTE)(aHookInfo[nHookIdx].lpNewProcAddr); //read original stub and create new one dwOsErr = lpHookEntry->CreateStub(int_data->sOptions.bOutputDebug, ((dwFlags & NKTHOOKLIB_DontSkipAnyJumps) == 0) ? TRUE : FALSE); if (dwOsErr != NO_ERROR) continue; //calculate inject code size and offset to data switch (cProcEntry->GetPlatform()) { case NKTHOOKLIB_PRocessPlatformX86: lpHookEntry->nInjCodeAndDataSize = 0x2A + lpHookEntry->nNewStubSize; break; #if defined _M_X64 case NKTHOOKLIB_PRocessPlatformX64: lpHookEntry->nInjCodeAndDataSize = 0x41 + lpHookEntry->nNewStubSize; break; #endif //_M_X64 } //allocate memory for inject code in target process NKT_ASSERT(lpHookEntry->nInjCodeAndDataSize < NKTHOOKLIB_PROCESS_MEMBLOCK_SIZE); lpHookEntry->lpInjCodeAndData = cProcEntry->AllocateStub(lpHookEntry->lpOrigProc); if (lpHookEntry->lpInjCodeAndData == NULL) { dwOsErr = ERROR_NOT_ENOUGH_MEMORY; continue; } //setup code switch (cProcEntry->GetPlatform()) { case NKTHOOKLIB_PRocessPlatformX86: NktHookLibHelpers::MemSet(aNewCode, 0x00, 8); //flags location NktHookLibHelpers::MemSet(aNewCode+0x08, 0x90, 8); //NOPs for hotpatching double hooks aNewCode[0x10] = 0x50; //push eax aNewCode[0x11] = 0xB8; //mov eax, ADDR lpInjCode *((ULONG NKT_UNALIGNED*)(aNewCode+0x12)) = (ULONG)(lpHookEntry->lpInjCodeAndData); aNewCode[0x16] = 0xF7; //test dword ptr [eax], 00000101h aNewCode[0x17] = 0x00; *((ULONG NKT_UNALIGNED*)(aNewCode+0x18)) = 0x00000101; aNewCode[0x1C] = 0x75; //jne @@1 ;if disabled/uninst aNewCode[0x1D] = 0x06; aNewCode[0x1E] = 0x58; //pop eax aNewCode[0x1F] = 0xE9; //jmp hooked proc *((ULONG NKT_UNALIGNED*)(aNewCode+0x20)) = (ULONG)(lpHookEntry->lpNewProc) - (ULONG)(lpHookEntry->lpInjCodeAndData) - 0x24; aNewCode[0x24] = 0x58; //@@1: pop eax lpHookEntry->lpCall2Orig = lpHookEntry->lpInjCodeAndData + 0x25; NktHookLibHelpers::MemCopy(aNewCode+0x25, lpHookEntry->aNewStub, lpHookEntry->nNewStubSize); //new stub aNewCode[0x25+lpHookEntry->nNewStubSize] = 0xE9; //jmp original proc after stub *((ULONG NKT_UNALIGNED*)(aNewCode+0x26+lpHookEntry->nNewStubSize)) = (ULONG)(lpHookEntry->lpOrigProc) + (ULONG)(lpHookEntry->nOriginalStubSize) - (ULONG)(lpHookEntry->lpInjCodeAndData+0x2A+lpHookEntry->nNewStubSize); break; #if defined _M_X64 case NKTHOOKLIB_PRocessPlatformX64: NktHookLibHelpers::MemSet(aNewCode, 0x00, 8); //flags location NktHookLibHelpers::MemSet(aNewCode+0x08, 0x90, 8); //NOPs for hotpatching double hooks aNewCode[0x10] = 0x50; //push rax aNewCode[0x11] = 0x48; //mov rax, ADDR lpInjCode aNewCode[0x12] = 0xB8; *((ULONGLONG NKT_UNALIGNED*)(aNewCode+0x13)) = (ULONGLONG)(lpHookEntry->lpInjCodeAndData); aNewCode[0x1B] = 0xF7; //test dword ptr [rax], 00000101h aNewCode[0x1C] = 0x00; *((ULONG NKT_UNALIGNED*)(aNewCode+0x1D)) = 0x00000101; aNewCode[0x21] = 0x75; //jne @@1 ;if disabled/uninst aNewCode[0x22] = 0x0F; aNewCode[0x23] = 0x58; //pop rax aNewCode[0x24] = 0xFF; //jmp hooked proc aNewCode[0x25] = 0x25; *((ULONG NKT_UNALIGNED*)(aNewCode+0x26)) = 0; *((ULONGLONG NKT_UNALIGNED*)(aNewCode+0x2A)) = (ULONGLONG)(lpHookEntry->lpNewProc); aNewCode[0x32] = 0x58; //@@1: pop rax lpHookEntry->lpCall2Orig = lpHookEntry->lpInjCodeAndData+0x33; NktHookLibHelpers::MemCopy(aNewCode+0x33, lpHookEntry->aNewStub, lpHookEntry->nNewStubSize); //new stub aNewCode[0x33+lpHookEntry->nNewStubSize] = 0xFF; //jmp original proc after stub aNewCode[0x34+lpHookEntry->nNewStubSize] = 0x25; *((ULONG NKT_UNALIGNED*)(aNewCode+0x35+lpHookEntry->nNewStubSize)) = 0; *((ULONGLONG NKT_UNALIGNED*)(aNewCode+0x39+lpHookEntry->nNewStubSize)) = (ULONGLONG)(lpHookEntry->lpOrigProc + lpHookEntry->nOriginalStubSize); break; #endif //_M_X64 } if (NktHookLibHelpers::WriteMem(cProcEntry->GetHandle(), lpHookEntry->lpInjCodeAndData, aNewCode, lpHookEntry->nInjCodeAndDataSize) == FALSE) { dwOsErr = ERROR_ACCESS_DENIED; continue; } //replace original proc with a jump dw = (DWORD)(lpHookEntry->lpInjCodeAndData+8) - (DWORD)(lpHookEntry->lpOrigProc) - 5; lpHookEntry->aJumpStub[0] = 0xE9; //JMP lpHookEntry->aJumpStub[1] = (BYTE)( dw & 0xFF); lpHookEntry->aJumpStub[2] = (BYTE)((dw >> 8) & 0xFF); lpHookEntry->aJumpStub[3] = (BYTE)((dw >> 16) & 0xFF); lpHookEntry->aJumpStub[4] = (BYTE)((dw >> 24) & 0xFF); //set id #if defined _M_IX86 lpHookEntry->nId = (SIZE_T)lpHookEntry ^ 0x34B68363UL; //odd number to avoid result of zero #elif defined _M_X64 lpHookEntry->nId = (SIZE_T)lpHookEntry ^ 0x34B68364A3CE19F3ui64; //odd number to avoid result of zero #endif //done aHookInfo[nHookIdx].nHookId = lpHookEntry->nId; aHookInfo[nHookIdx].lpCallOriginal = lpHookEntry->lpCall2Orig; } //hook new items if (dwOsErr == NO_ERROR) { NktHookLib::CNktThreadSuspend::CAutoResume cAutoResume(&(int_data->cThreadSuspender)); NktHookLib::CNktThreadSuspend::IP_RANGE sIpRanges[MAX_SUSPEND_IPRANGES]; SIZE_T k, k2, nThisRoundSuspCount; MEMORY_BASIC_INFORMATION sMbi; HOOK_INFO sHooks[64]; DWORD dwNewProt, dwOldProt; for (nHookIdx=nThisRoundSuspCount=0; nHookIdx<nCount && dwOsErr==NO_ERROR; ) { if (nThisRoundSuspCount == 0) { //suspend threads nThisRoundSuspCount = (nCount-nHookIdx > MAX_SUSPEND_IPRANGES) ? MAX_SUSPEND_IPRANGES : (nCount-nHookIdx); for (k=0; k<nThisRoundSuspCount; k++) { sIpRanges[k].nStart = (SIZE_T)(lpNewEntriesList[nHookIdx+k]->lpOrigProc); sIpRanges[k].nEnd = sIpRanges[k].nStart + HOOKENG_JUMP_TO_HOOK_SIZE; } dwOsErr = NO_ERROR; if (int_data->sOptions.bSuspendThreads != FALSE) dwOsErr = int_data->cThreadSuspender.SuspendAll(cProcEntry->GetPid(), sIpRanges, nThisRoundSuspCount); if (dwOsErr != NO_ERROR) { err_uninstall_and_destroy: for (nHookIdx=k2=0; nHookIdx<nCount; nHookIdx++) { if (lpNewEntriesList[nHookIdx]->nInstalledCode != 0) { sHooks[k2++].nHookId = lpNewEntriesList[nHookIdx]->nId; if (k2 >= X_ARRAYLEN(sHooks)) { Unhook(sHooks, k2); k2 = 0; } } } if (k2 > 0) Unhook(sHooks, k2); continue; } } for (k=0; k<nThisRoundSuspCount; k++) { k2 = 0; lpPtr = lpNewEntriesList[nHookIdx+k]->lpOrigProc; NktHookLibHelpers::MemSet(&sMbi, 0, sizeof(sMbi)); nNtStatus = NktHookLib::NktNtQueryVirtualMemory(cProcEntry->GetHandle(), lpPtr, MyMemoryBasicInformation, &sMbi, sizeof(sMbi), &k2); dwNewProt = PAGE_EXECUTE_WRITECOPY; if (NT_SUCCESS(nNtStatus)) { switch (sMbi.Protect & 0xFF) { case PAGE_NOACCESS: case PAGE_READONLY: case PAGE_READWRITE: dwNewProt = PAGE_READWRITE; break; case PAGE_WRITECOPY: dwNewProt = PAGE_WRITECOPY; break; case PAGE_EXECUTE: case PAGE_EXECUTE_READ: case PAGE_EXECUTE_READWRITE: dwNewProt = PAGE_EXECUTE_READWRITE; break; } } //change protection if needed if (dwNewProt != (sMbi.Protect & 0xFF)) { dwOldProt = 0; nSize = HOOKENG_JUMP_TO_HOOK_SIZE; nNtStatus = NktHookLib::NktNtProtectVirtualMemory(cProcEntry->GetHandle(), (PVOID*)&lpPtr, &nSize, dwNewProt, &dwOldProt); if (!NT_SUCCESS(nNtStatus)) { dwOsErr = NktHookLib::NktRtlNtStatusToDosError(nNtStatus); if (dwOsErr == 0) dwOsErr = ERROR_NOT_SUPPORTED; int_data->cThreadSuspender.ResumeAll(); goto err_uninstall_and_destroy; } } //replace each entry point k2 = (NktHookLibHelpers::WriteMem(cProcEntry->GetHandle(), lpNewEntriesList[nHookIdx+k]->lpOrigProc, lpNewEntriesList[nHookIdx+k]->aJumpStub, HOOKENG_JUMP_TO_HOOK_SIZE) != FALSE) ? 1 : 0; //restore protection if (dwNewProt != (sMbi.Protect & 0xFF)) { lpPtr = lpNewEntriesList[nHookIdx+k]->lpOrigProc; nSize = HOOKENG_JUMP_TO_HOOK_SIZE; NktHookLib::NktNtProtectVirtualMemory(cProcEntry->GetHandle(), (PVOID*)&lpPtr, &nSize, dwOldProt, &dw); } //check write operation result if (k2 == 0) { dwOsErr = ERROR_ACCESS_DENIED; int_data->cThreadSuspender.ResumeAll(); goto err_uninstall_and_destroy; } //flush instruction cache NktHookLib::NktNtFlushInstructionCache(cProcEntry->GetHandle(), lpNewEntriesList[nHookIdx+k]->lpOrigProc, 32); //mark as installed lpNewEntriesList[nHookIdx+k]->nInstalledCode = 1; } //advance count nHookIdx += nThisRoundSuspCount; //check if we can proceed with the next hook with this nThisRoundSuspCount = 0; for (k=nHookIdx; k<nCount; k++) { k2 = (SIZE_T)(lpNewEntriesList[k]->lpOrigProc); if (int_data->cThreadSuspender.CheckIfThreadIsInRange(k2, k2+HOOKENG_JUMP_TO_HOOK_SIZE) == FALSE) break; nThisRoundSuspCount++; } if (nThisRoundSuspCount == 0) { //resume threads int_data->cThreadSuspender.ResumeAll(); } } } //done... move to the final list or delete on error if (dwOsErr == NO_ERROR) { for (nHookIdx=0; nHookIdx<nCount; nHookIdx++) { lpNewEntriesList[nHookIdx]->dwFlags = dwFlags; if (int_data->sOptions.bOutputDebug != FALSE) { NktHookLibHelpers::DebugPrint("NktHookLib: Hook installed. Proc @ 0x%IX -> 0x%IX (Stub @ 0x%IX) \r\n", (SIZE_T)(lpNewEntriesList[nHookIdx]->lpOrigProc), (SIZE_T)(lpNewEntriesList[nHookIdx]->lpNewProc), (SIZE_T)(lpNewEntriesList[nHookIdx]->lpInjCodeAndData)); } int_data->cHooksList.PushTail(lpNewEntriesList[nHookIdx]); } } else { for (nHookIdx=0; nHookIdx<nCount; nHookIdx++) delete lpNewEntriesList[nHookIdx]; } if (lpNewEntriesList != NULL) NktHookLibHelpers::MemFree(lpNewEntriesList); }