i have injected my DLL into process and i try to scan memory for addresses with same value as mine, but it results in a crash after i get 1st address , it should be 10 addresses
for(DWORD i = MEM_START; i< MEM_END ;i++)
{
VirtualQuery((void*)i,pMemInfo,sizeof(MEMORY_BASIC_INFORMATION));
if(pMemInfo->AllocationProtect == PAGE_READONLY || PAGE_EXECUTE_WRITECOPY || PAGE_READWRITE || PAGE_WRITECOMBINE)
{
if(*(DWORD*)i==1337)
{
addresses.push_back(i);
}
}
}
I believe my protection check is wrong but not quite sure.
virtual memory scanner
MEMORY_BASIC_INFORMATION mbi = {0};
unsigned char *pAddress = NULL,
*pEndRegion = NULL;
DWORD dwFindData = 0xBAADF00D,
dwProtectionMask = PAGE_READONLY | PAGE_EXECUTE_WRITECOPY
| PAGE_READWRITE | PAGE_WRITECOMBINE;
while( sizeof(mbi) == VirtualQuery(pEndRegion, &mbi, sizeof(mbi)) ){
pAddress = pEndRegion;
pEndRegion += mbi.RegionSize;
if ((mbi.AllocationProtect & dwProtectionMask) && (mbi.State & MEM_COMMIT)){
for (pAddress; pAddress < pEndRegion ; pAddress++){
if (*pAddress == dwFindData){
// dostaff
}
}
}
}
Yes, several mistakes. You'll need to use the | operator instead of ||. The value of i is not meaningful, you must use MEMORY_BASIC_INFORMATION.AllocationBase to find where a region begins. And .RegionSize to know how big it is. The next value you pass to VirtualQuery should be .AllocationBase + .RegionSize to find the next region.
That's not how the || operator works. You may find it more readable to use a switch statement instead.
for (DWORD i = MEM_START; i < MEM_END ;i++)
{
VirtualQuery((void*)i, pMemInfo, sizeof(MEMORY_BASIC_INFORMATION));
switch (pMemInfo->AllocationProtect)
{
case PAGE_READONLY:
case PAGE_EXECUTE_WRITECOPY:
case PAGE_READWRITE:
case PAGE_WRITECOMBINE:
if(*(DWORD*)i==1337)
{
addresses.push_back(i);
}
}
}
Related
I'm currently trying to process the absolute value of a drawing tablet's touch ring, through the Wintab API. However, despite following instructions as they are described in the documentation, it seems like the WTOpen call doesn't set any extension settings. Using the touch ring after initializing Wintab still triggers the default events, while the default events for pen inputs are suppressed and all pen inputs related to my application instead.
Here are the relevant segments of code:
...
#include "wintab.h"
#define PACKETDATA (PK_X | PK_Y | PK_Z | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_TIME | PK_BUTTONS)
#define PACKETMODE 0
#define PACKETTOUCHSTRIP PKEXT_ABSOLUTE
#define PACKETTOUCHRING PKEXT_ABSOLUTE
#include "pktdef.h"
...
internal b32
InitWinTab(HWND Window, window_mapping *Map)
{
if(!LoadWintabFunctions())
return false;
LOGCONTEXT Tablet;
AXIS TabletX, TabletY, TabletZ, Pressure;
if(!gpWTInfoA(WTI_DEFCONTEXT, 0, &Tablet))
return false;
gpWTInfoA(WTI_DEVICES, DVC_X, &TabletX);
gpWTInfoA(WTI_DEVICES, DVC_Y, &TabletY);
gpWTInfoA(WTI_DEVICES, DVC_Z, &TabletZ);
gpWTInfoA(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
UINT TouchStripOffset = 0xFFFF;
UINT TouchRingOffset = 0xFFFF;
for(UINT i = 0, ScanTag = 0; gpWTInfoA(WTI_EXTENSIONS + i, EXT_TAG, &ScanTag); i++)
{
if (ScanTag == WTX_TOUCHSTRIP)
TouchStripOffset = i;
if (ScanTag == WTX_TOUCHRING)
TouchRingOffset = i;
}
Tablet.lcOptions |= CXO_MESSAGES;
Tablet.lcPktData = PACKETDATA;
Tablet.lcPktMode = PACKETMODE;
Tablet.lcMoveMask = PACKETDATA;
Tablet.lcBtnUpMask = Tablet.lcBtnDnMask;
Tablet.lcInOrgX = 0;
Tablet.lcInOrgY = 0;
Tablet.lcInExtX = TabletX.axMax;
Tablet.lcInExtY = TabletY.axMax;
if(TouchStripOffset != 0xFFFF)
{
WTPKT DataMask;
gpWTInfoA(WTI_EXTENSIONS + TouchStripOffset, EXT_MASK, &DataMask);
Tablet.lcPktData |= DataMask;
}
if(TouchRingOffset != 0xFFFF)
{
WTPKT DataMask;
gpWTInfoA(WTI_EXTENSIONS + TouchRingOffset, EXT_MASK, &DataMask);
Tablet.lcPktData |= DataMask;
}
Map->AxisMax.x = (r32)TabletX.axMax;
Map->AxisMax.y = (r32)TabletY.axMax;
Map->AxisMax.z = (r32)TabletZ.axMax;
Map->PressureMax = (r32)Pressure.axMax;
if(!gpWTOpenA(Window, &Tablet, TRUE))
return false;
return(TabletX.axMax && TabletY.axMax && TabletZ.axMax && Pressure.axMax);
}
...
case WT_PACKET:
{
PACKET Packet;
if(gpWTPacket((HCTX)LParam, (UINT)WParam, &Packet))
{
...
}
} break;
case WT_PACKETEXT:
{
PACKETEXT Packet;
if(gpWTPacket((HCTX)LParam, (UINT)WParam, &Packet))
{
...
}
} break;
...
The bitmask for the packet data in the initialization have sensible bits set for both extensions and don't overlap with the existing bitmask. No stage of the initialization fails. WT_PACKET gets called only with valid packet data while WT_PACKETEXT never gets called. Furthermore, calling WTPacketsGet with a PACKETEXT pointer on the HCTX returned by WTOpen fills the packet with garbage from the regular packet queue. This leaves me with the conclusion that somehow WTOpen didn't receive notification that the extensions should be loaded and I'm unable to find what else I should define in the LOGCONTEXT data structure to change that.
Is there a mistake in my initialization? Or is there a way to get a better readout to why the extensions didn't load?
It turned out that a driver setting prevented the extension packets from being sent, in favor of using the touch ring for different function. Changing this setting resolved the issue. The code didn't contain any errors itself.
My goal is to understand stack unwinding in 64-bit PE32+ executable format in Windows, or how the following API can calculate addresses of a function prologue, body, epilogue, etc.:
CONTEXT context = {0};
RtlCaptureContext(&context);
DWORD64 ImgBase = 0;
RUNTIME_FUNCTION* pRTFn = RtlLookupFunctionEntry(context.Rip, &ImgBase, NULL);
_tprintf(L"Prologue=0x%p\n", (void*)(ImgBase + pRTFn->BeginAddress));
I know that the information on the offsets of all non-leaf functions used by the linker is included in the PE32+ header in the exceptions directory. So I tried to write my own function to parse it. I got to this point where I got stumped:
//INFO -- must be compiled as x64 only!
void GetFunctionTable(BYTE* lpBaseAddress, size_t szImageSz)
{
if(lpBaseAddress)
{
if(szImageSz > sizeof(IMAGE_DOS_HEADER))
{
IMAGE_DOS_HEADER* pDOSHeader = (IMAGE_DOS_HEADER*)lpBaseAddress;
if(pDOSHeader->e_magic == IMAGE_DOS_SIGNATURE)
{
IMAGE_NT_HEADERS* pNtHeader = (IMAGE_NT_HEADERS*)((BYTE*)pDOSHeader + pDOSHeader->e_lfanew);
PIMAGE_DATA_DIRECTORY pDataDirectories = NULL;
if(pNtHeader->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
{
//64-bit image only
IMAGE_NT_HEADERS64* pHdr64 = (IMAGE_NT_HEADERS64*)pNtHeader;
IMAGE_OPTIONAL_HEADER64* pIOH64 = &pHdr64->OptionalHeader;
pDataDirectories = pIOH64->DataDirectory;
IMAGE_DATA_DIRECTORY* pExceptDir = &pDataDirectories[IMAGE_DIRECTORY_ENTRY_EXCEPTION];
if(pExceptDir->VirtualAddress &&
pExceptDir->Size)
{
IMAGE_RUNTIME_FUNCTION_ENTRY* pRFs = (IMAGE_RUNTIME_FUNCTION_ENTRY*)
GetPtrFromRVA64(pExceptDir->VirtualAddress, pNtHeader, lpBaseAddress);
//'pRFs' = should point to an array of RUNTIME_FUNCTION structs
// but in my case it points to an empty region of memory with all zeros.
}
}
}
}
}
}
with the following helper functions:
PIMAGE_SECTION_HEADER GetEnclosingSectionHeader64(DWORD_PTR rva, PIMAGE_NT_HEADERS64 pNTHeader)
{
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(pNTHeader);
unsigned int i;
for ( i=0; i < pNTHeader->FileHeader.NumberOfSections; i++, section++ )
{
if ( (rva >= section->VirtualAddress) &&
(rva < (section->VirtualAddress + section->Misc.VirtualSize)))
return section;
}
return 0;
}
LPVOID GetPtrFromRVA64(DWORD rva, const void* pNTHeader, const void* imageBase)
{
PIMAGE_SECTION_HEADER pSectionHdr;
INT_PTR delta;
pSectionHdr = GetEnclosingSectionHeader64( rva, (PIMAGE_NT_HEADERS64)pNTHeader );
if ( !pSectionHdr )
return 0;
delta = (INT_PTR)(pSectionHdr->VirtualAddress - pSectionHdr->PointerToRawData);
return (PVOID) ( (BYTE*)imageBase + rva - delta );
}
So I'm testing it on the self executable:
HMODULE hMod = ::GetModuleHandle(NULL);
MODULEINFO mi = {0};
if(::GetModuleInformation(::GetCurrentProcess(), hMod, &mi, sizeof(mi)))
{
GetFunctionTable((BYTE*)hMod, mi.SizeOfImage);
}
But the problem is that inside my GetFunctionTable when I try to look up the function table mapped in memory in the IMAGE_DIRECTORY_ENTRY_EXCEPTION directory, I'm getting a pointer (i.e. IMAGE_RUNTIME_FUNCTION_ENTRY*) to an empty region of memory. I must be not translating the rva address correctly.
So anyone who knows how PE32+ header is mapped in memory, can please show what am I doing wrong there?
I'm trying to share an array of structs through shared named memory using the WINAPI. I'm able to create and manage the shared memory but when trying to share an array of structs the size of the array is always 0 upon reading.
Below is test code i have written which should write/read an array of 10 entries, but even this is failing. My goal is however to write/read a dynamic array of structs containing 2 dynamic arrays and the info they already contain at the moment.
I'm aware i shouldn't share pointers between processes as they could point to a random value. Therefor i'm allocating memory for the arrays using new.
This is what i have so far:
Shared in both processes:
#define MEMSIZE 90024
typedef struct {
int id;
int type;
int count;
} Entry;
Process 1:
extern HANDLE hMapObject;
extern void* vMapData;
std::vector<Entry> entries;//collection of entries
BOOL DumpEntries(TCHAR* memName) {//Returns true, writing 10 entries
int size = min(10, entries.size());
Entry* eArray = new Entry[size];
for (int i = 0; i < size; i++) {
eArray[i] = entries.at(i);
}
::hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MEMSIZE, memName);
if (::hMapObject == NULL) {
return FALSE;
}
::vMapData = MapViewOfFile(::hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, MEMSIZE);
if (::vMapData == NULL) {
CloseHandle(::hMapObject);
return FALSE;
}
CopyMemory(::vMapData, eArray, (size * sizeof(Entry)));
UnmapViewOfFile(::vMapData);
//delete[] eArray;
return TRUE;
}
Process 2:
BOOL ReadEntries(TCHAR* memName, Entry* entries) {//Returns true reading 0 entries
HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, memName);
if (hMapFile == NULL) {
return FALSE;
}
Entry* tmpEntries = (Entry*)(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 10 * sizeof(Entry)));
if (tmpEntries == NULL) {
CloseHandle(hMapFile);
return FALSE;
}
entries = new Entry[10];
for (int i = 0; i < 10; i++) {
entries[i] = tmpEntries[i];
}
UnmapViewOfFile(tmpEntries);
CloseHandle(hMapFile);
return TRUE;
}
Writing the 10 entries seems to be working but when trying to read the memory it returns successfully and the size
of the array is 0, like so:
Entry* entries = NULL;
if (ReadEntries(TEXT("Global\Entries"), entries)) {
int size = _ARRAYSIZE(entries);
out = "Succesfully read: " + to_string(size);// Is always 0
}
So my question is, what am I doing wrong? I'm sharing the same struct between 2 processes, i'm allocating new memory for the entries to be written to and copying the memory with a size of 10 * sizeof(Entry);. When trying to read I also try to read 10 * sizeof(Entry); bytes and cast the data to a Entry*. Is there something I'm missing? All help is welcome.
Based on cursory examination, this code appears to attempt to map structures containing std::strings into shared memory, to be used by another process.
Unfortunately, this adventure is doomed, before it even gets started. Even if you get the array length to pass along correctly, I expect the other process to crash immediately, as soon as it even smells the std::string that the other process attempted to map into shared memory segments.
std::strings are non-trivial classes. A std::string maintains internal pointers to a buffer where the actual string data is kept; with the buffer getting allocated on the heap.
You do understand that sizeof(std::string) doesn't change, whether the string contains five characters, or the entire contents of "War And Peace", right? Stop and think for a moment, how that's possible, in just a few bytes that it takes to store a std::string?
Once you think about it for a moment, it should become crystal clear why mapping one process's std::strings into a shared memory segment, and then attempting to grab them by another process, is not going to work.
The only thing that can be practically mapped to/from shared memory is plain old data; although you could get away with aggregates, in some cases, too.
I'm afraid the problem only lies in the _ARRAYSIZE macro. I could not really find it in MSDN, but I found references for _countof or ARRAYSIZE in other pages. All are defined as sizeof(array)/sizeof(array[0]). The problem is that it only make sense for true arrays defined as Entry entries[10], but not for a pointer to such an array. Technically when you declare:
Entry* entries;
sizeof(entries) is sizeof(Entry *) that is the size of a pointer. It is smaller than the size of the struct so the result of the integer division is... 0!
Anyway, there are other problems in current code. The correct way to exchange a variable size array through shared memory is to use an ancillary structure containing a size and the array itself declared as incomplete:
struct EntryArray {
size_t size;
Entry entries[];
};
You could dump it that way:
BOOL DumpEntries(TCHAR* memName) {//Returns true, writing 10 entries
int size = min(10, entries.size());
EntryArray* eArray = (EntryArray *) malloc(sizeof(EntryArray) + size * sizeof(Entry));
for (int i = 0; i < size; i++) {
eArray->entries[i] = entries.at(i);
}
eArray->size = size;
::hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MEMSIZE, memName);
if (::hMapObject == NULL) {
return FALSE;
}
::vMapData = MapViewOfFile(::hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, MEMSIZE);
if (::vMapData == NULL) {
CloseHandle(::hMapObject);
return FALSE;
}
CopyMemory(::vMapData, eArray, (sizeof(EntryArray) + size * sizeof(Entry)));
UnmapViewOfFile(::vMapData);
free(eArray);
return TRUE;
}
You can note that as the last member of the struct is an incomplete array, it is allocated 0 size, so you must allocate the size of the struct + the size of the array.
You can then read it from memory that way:
size_t ReadEntries(TCHAR* memName, Entry*& entries) {//Returns the number of entries or -1 if error
HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, memName);
if (hMapFile == NULL) {
return -1;
}
EntryArray* eArray = (EntryArray*)(MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 10 * sizeof(Entry)));
if (eArray == NULL) {
CloseHandle(hMapFile);
return -1;
}
entries = new Entry[10]; // or even entries = new Entry[eArray->size];
for (int i = 0; i < 10; i++) { // same: i<eArray->size ...
entries[i] = eArray->entries[i];
}
UnmapViewOfFile(eArray);
CloseHandle(hMapFile);
return eArray.size;
}
But here again you should note some differences. As the number of entries is lost when eArray vanishes, it is passed as the return value from the function. And and you want to modify the pointer passed as second parameter, you must pass it by reference (if you pass it by value, you will only change a local copy and still have NULL in original variable after function returns).
There are still some possible improvement in your code, because the vector entries is global when it could be passed as a parameter to DumpEntries, and hMapObject is also global when it could be returned by the function. And in DumpObject you could avoid a copy by building directly the EntryArray in shared memory:
HANDLE DumpEntries(TCHAR* memName, const std::vector<Entry>& entries) {
//Returns HANDLE to mapped file (or NULL), writing 10 entries
int size = min(10, entries.size());
HANDLE hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, MEMSIZE, memName);
if (hMapObject == NULL) {
return NULL;
}
void * vMapData = MapViewOfFile(hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, MEMSIZE);
if (vMapData == NULL) {
CloseHandle(hMapObject);
return NULL;
}
EntryArray* eArray = (EntryArray*) vMapData;
for (int i = 0; i < size; i++) {
eArray->entries[i] = entries.at(i);
}
eArray->size = size;
UnmapViewOfFile(vMapData);
return hMapObject;
}
And last but not least, the backslash \ is a special quoting character in a string litteral, and it must quote itself. So you should write .TEXT("Global\\Entries")
I did it some changes to your code:
PROCESS 1:
BOOL DumpEntries(TCHAR* memName)
{
int size = entries.size() * sizeof(Entry) + sizeof(DWORD);
::hMapObject = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, memName);
if (::hMapObject == NULL) {
return FALSE;
}
::vMapData = MapViewOfFile(::hMapObject, FILE_MAP_ALL_ACCESS, 0, 0, size);
if (::vMapData == NULL) {
CloseHandle(::hMapObject);
return FALSE;
}
(*(DWORD*)::vMapData) = entries.size();
Entry* eArray = (Entry*)(((DWORD*)::vMapData) + 1);
for(int i = entries.size() - 1; i >= 0; i--) eArray[i] = entries.at(i);
UnmapViewOfFile(::vMapData);
return TRUE;
}
PROCESS 2:
BOOL ReadEntries(TCHAR* memName, Entry** entries, DWORD &number_of_entries) {
HANDLE hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, memName);
if (hMapFile == NULL) {
return FALSE;
}
DWORD *num_entries = (DWORD*)MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (num_entries == NULL) {
CloseHandle(hMapFile);
return FALSE;
}
number_of_entries = *num_entries;
if(number_of_entries == 0)
{
// special case: when no entries was found in buffer
*entries = NULL;
return true;
}
Entry* tmpEntries = (Entry*)(num_entries + 1);
*entries = new Entry[*num_entries];
for (UINT i = 0; i < *num_entries; i++) {
(*entries)[i] = tmpEntries[i];
}
UnmapViewOfFile(num_entries);
CloseHandle(hMapFile);
return TRUE;
}
PROCESS 2 (usage example):
void main()
{
Entry* entries;
DWORD number_of_entries;
if(ReadEntries(TEXT("Global\\Entries", &entries, number_of_entries) && number_of_entries > 0)
{
// do something
}
delete entries;
}
CHANGES:
I am not using a static size (MEMSIZE) when i map memory, i am calculating exactly memory requiered
I put a "header" to memory mapped, a DWORD for send to process 2 number of entries in buffer
your ReadEntries definition is wrong, i fix it changing Entry* to Entry**
NOTES:
you need to close ::hMapObject handle in process 1 before process 2 calls ReadEntries
you need to delete entries memory returned for ReadEntries in process 2, before you use it
this code works only under same windows user, if you want to communicate a services with user process (for example), you need to handle SECURITY_ATTRIBUTES member in CreateFileMapping procedure
I have an application that tries to verify the mmc.exe (services) signature. (the context of the application I think is irrelevant) I am trying with winapi function which both fails with
WinVerifyTrust. I get TRUST_E_BAD_DIGEST when I am trying with verification from catalog, and
TRUST_E_NOSIGNATURE when trying from file info. it is very important to mention that my function succeeds on win7, XP but fails on win8.
this is the code snippet for the function
CATALOG_INFO InfoStruct = {0};
InfoStruct.cbStruct = sizeof(CATALOG_INFO);
WINTRUST_CATALOG_INFO WintrustCatalogStructure = {0};
WintrustCatalogStructure.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
WINTRUST_FILE_INFO WintrustFileStructure = {0};
WintrustFileStructure.cbStruct = sizeof(WINTRUST_FILE_INFO);
GUID ActionGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
//Get a context for signature verification.
HCATADMIN Context = NULL;
if(!::CryptCATAdminAcquireContext(&Context, NULL, 0) ){
return false;
}
//Open file.
cx_handle hFile(::CreateFileW(filename_.c_str(), GENERIC_READ, 7, NULL, OPEN_EXISTING, 0, NULL));
if( INVALID_HANDLE_VALUE == (HANDLE)hFile )
{
CryptCATAdminReleaseContext(Context, 0);
return false;
}
//Get the size we need for our hash.
DWORD HashSize = 0;
::CryptCATAdminCalcHashFromFileHandle(hFile, &HashSize, NULL, 0);
if( HashSize == 0 )
{
//0-sized has means error!
::CryptCATAdminReleaseContext(Context, 0);
return false;
}
//Allocate memory.
buffer hashbuf(HashSize);
//Actually calculate the hash
if( !CryptCATAdminCalcHashFromFileHandle(hFile, &HashSize, hashbuf.data, 0) )
{
CryptCATAdminReleaseContext(Context, 0);
return false;
}
//Convert the hash to a string.
buffer MemberTag(((HashSize * 2) + 1) * sizeof(wchar_t));
for( unsigned int i = 0; i < HashSize; i++ ){
swprintf(&((PWCHAR)MemberTag.data)[i * 2], L"%02X", hashbuf.data[i ]);
}
//Get catalog for our context.
HCATINFO CatalogContext = CryptCATAdminEnumCatalogFromHash(Context, hashbuf, HashSize, 0, NULL);
if ( CatalogContext )
{
//If we couldn't get information
if ( !CryptCATCatalogInfoFromContext(CatalogContext, &InfoStruct, 0) )
{
//Release the context and set the context to null so it gets picked up below.
CryptCATAdminReleaseCatalogContext(Context, CatalogContext, 0);
CatalogContext = NULL;
}
}
//If we have a valid context, we got our info.
//Otherwise, we attempt to verify the internal signature.
WINTRUST_DATA WintrustStructure = {0};
WintrustStructure.cbStruct = sizeof(WINTRUST_DATA);
if( !CatalogContext )
{
load_signature_verification_from_file_info(WintrustFileStructure, WintrustStructure);
}
else
{
load_signature_verification_from_catalog(WintrustStructure, WintrustCatalogStructure, InfoStruct, MemberTag);
}
//Call our verification function.
long verification_res = ::WinVerifyTrust(0, &ActionGuid, &WintrustStructure);
//Check return.
bool is_success = SUCCEEDED(verification_res) ? true : false;
// if failed with CatalogContext, try with FILE_INFO
if(!is_success && CatalogContext && verification_res != TRUST_E_NOSIGNATURE)
{
//warning2(L"Failed verification with Catalog Context: 0x%x %s ; Retrying with FILE_INFO.", verification_res, (const wchar_t*)format_last_error(verification_res));
load_signature_verification_from_file_info(WintrustFileStructure, WintrustStructure);
verification_res = ::WinVerifyTrust(0, &ActionGuid, &WintrustStructure);
is_success = SUCCEEDED(verification_res) ? true : false;
}
if(perr && !is_success && verification_res != TRUST_E_NOSIGNATURE)
{
perr->code = verification_res;
perr->description = format_last_error(verification_res);
}
//Free context.
if( CatalogContext ){
::CryptCATAdminReleaseCatalogContext(Context, CatalogContext, 0);
}
//If we successfully verified, we need to free.
if( is_success )
{
WintrustStructure.dwStateAction = WTD_STATEACTION_CLOSE;
::WinVerifyTrust(0, &ActionGuid, &WintrustStructure);
}
::CryptCATAdminReleaseContext(Context, 0);
return is_success;
I don't think any thing had changed in this function from win7 to win 8 so what could possibly go wrong?
UPDATE
I did notice that my function does work for task manager at win 8.
but again for the mmc it does not work.
It appears that your general approach is correct and the functions themselves haven't changed. However there are subtle changes; namely the data on which they operate has changed. The hashes stored for files on Windows 8, according to comments on CryptCATAdminCalcHashFromFileHandle, are calculated using SHA-256 hashes.
The SHA-256 hashing algorithm is not supported by CryptCATAdminCalcHashFromFileHandle, so you must update the code to use CryptCATAdminAcquireContext2 and CryptCATAdminCalcHashFromFileHandle2 on Windows 8; the former allows you to acquire a HCATADMIN with a specified hash algorithm, and the latter allows using that HCATADMIN.
(Interestingly, WINTRUST_CATALOG_INFO also points this direction with its HCATADMIN hCatAdmin member, documented as "Windows 8 and Windows Server 2012: Support for this member begins.")
I'd like to ask, how could I locate a specific (exported) function inside a DLL. For example I'd like to locate ReadProcessMemory inside Kernel32. I wouldn't like to rely on Import table, I'd like to locate different APIs based on their addresses what I get with a custom function.
I tried to make a small research on VA, RVA & File offsets, but I didn't succeed. Here's an example which I tried, but it isn't working (returns 0 in all cases):
DWORD Rva2Offset(DWORD dwRva, UINT_PTR uiBaseAddress)
{
WORD wIndex = 0;
PIMAGE_SECTION_HEADER pSectionHeader = NULL;
PIMAGE_NT_HEADERS pNtHeaders = NULL;
pNtHeaders = (PIMAGE_NT_HEADERS) (uiBaseAddress + ((PIMAGE_DOS_HEADER) uiBaseAddress)->e_lfanew);
pSectionHeader = (PIMAGE_SECTION_HEADER) ((UINT_PTR) (&pNtHeaders->OptionalHeader) + pNtHeaders->FileHeader.SizeOfOptionalHeader);
if (dwRva < pSectionHeader[0].PointerToRawData)
return dwRva;
for (wIndex = 0; wIndex < pNtHeaders->FileHeader.NumberOfSections; wIndex++)
{
if (dwRva >= pSectionHeader[wIndex].VirtualAddress && dwRva < (pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].SizeOfRawData))
return (dwRva - pSectionHeader[wIndex].VirtualAddress + pSectionHeader[wIndex].PointerToRawData);
}
return 0;
}
Could you help me how could I accomplish this simple task?
Thank you.
P.s.: I'm not sticking to the function above, both if you can point out what's the problem, or give a better source would be awesome.
This gives you the relative virtual address
uintptr_t baseAddr = (uintptr_t)GetModuleHandle("nameOfExe.exe");
uintptr_t relativeAddr = functionAddress - baseAddr;
This converts relative virtual address to File offset:
DWORD RVAToFileOffset(IMAGE_NT_HEADERS32* pNtHdr, DWORD dwRVA)
{
int i;
WORD wSections;
PIMAGE_SECTION_HEADER pSectionHdr;
pSectionHdr = IMAGE_FIRST_SECTION(pNtHdr);
wSections = pNtHdr->FileHeader.NumberOfSections;
for (i = 0; i < wSections; i++)
{
if (pSectionHdr->VirtualAddress <= dwRVA)
if ((pSectionHdr->VirtualAddress + pSectionHdr->Misc.VirtualSize) > dwRVA)
{
dwRVA -= pSectionHdr->VirtualAddress;
dwRVA += pSectionHdr->PointerToRawData;
return (dwRVA);
}
pSectionHdr++;
}
return (-1);
}