How do I get stack call information in an x64 program? - c++

I found a way to get the information of the stack call in an x86 program. The code is not difficult to understand:
#ifdef X86
void TestGetCallStack_X86()
{
std::cout << "Call -> TestGetCallStack_X86" << std::endl;
std::cout << "***************************************" << std::endl;
DWORD _ebp, _esp;
__asm mov _ebp, ebp
__asm mov _esp, esp
for (unsigned int index = 0; index < CALLSTACK_NUM; index++) {
void* pAddr = (void*)ULongToPtr(*(((DWORD*)ULongToPtr(_ebp)) + 1));
if (!pAddr)
return;
IMAGEHLP_LINE64 Line;
Line.SizeOfStruct = sizeof(Line);
memset(&Line, 0, sizeof(Line));
DWORD Offset = 0;
if (fnSymGetLineFromAddr64(s_Process, (DWORD64)pAddr, &Offset, &Line))
{
std::cout << index << " [" << pAddr << "]";
std::cout << " File Name:" << Line.FileName << " " << "Line Count:" << Line.LineNumber << std::endl;
std::cout << std::endl;
}
else
{
DWORD error = GetLastError();
if (error == 487)
{
OutputDebugString(TEXT("No debug info in current module\n"));
}
else if (error == 126)
{
OutputDebugString(TEXT("Debug info in current module has not loaded\n"));
}
else
{
OutputDebugString(TEXT("SymGetLineFromAddr64 failed\n"));
}
std::cout << std::endl;
}
_ebp = *(DWORD*)ULongToPtr(_ebp);
if (_ebp == 0 || 0 != (_ebp & 0xFC000000) || _ebp < _esp)
break;
}
std::cout << "***************************************" << std::endl;
}
#endif // X86
run result
I wrote an x64 version and found that MSVC for x64 does't support inline assembly.
I try to write a .asm file and load the function in C++ code. but it does't work. (Actually I'm not good at Assembly language)
I found many ways. So far, I have used the _ReturnAddress to achieve.
void TestGetCallStack_X64()
{
void* pAddr = _ReturnAddress();
if (!pAddr)
return;
std::cout << "0" << "\t" << pAddr << std::endl;
std::cout << "Use GetLineFromAddress64:" << std::endl;
IMAGEHLP_LINE64 Line;
Line.SizeOfStruct = sizeof(Line);
memset(&Line, 0, sizeof(Line));
DWORD Offset = 0;
if (fnSymGetLineFromAddr64(s_Process, (DWORD64)pAddr, &Offset, &Line))
{
std::cout << "File Name:" << Line.FileName << "\t" << "Line Count:" << Line.LineNumber << std::endl;
std::cout << std::endl;
}
else
{
//Can not find...
}
}
Run Result
But this way cannot fully display the information of the stack call. How should I achieve the same effect as the x86 version?
PS: I can't understand the condition of break in x86's Code. Can anyone answer, Please! Thank you first.
//what's the mean that <_ebp & 0xFC000000>
if (_ebp == 0 || 0 != (_ebp & 0xFC000000) || _ebp < _esp)

Related

QueryChangesVirtualDisk is returning ERROR_INVALID_HANDLE(6) even though OpenVirtualDisk is succesfull

I am trying out VirtualDisk APIs,
So far I am able to Open a VHDX file, get some of the properties by using GetVirtualDiskInformation.
But I am not able to get RCT information and ChangedAreas.
The first call to GetVirtualDiskInformation is successful.
The second call to GetVirtualDiskInformation fails with insufficient buffer ERROR_INSUFFICIENT_BUFFER(122).
Call to QueryChangesVirtualDisk fails with ERROR_INVALID_HANDLE(6).
The RCT ID hardcoded in the code is proper, I am able to get the ChangedAreas using WMI Explorer.
Attached screenshot of the same.
If it is invalid handle, then GetVirtualDiskInformation should also throw the same error?
#include "pch.h"
#include <iostream>
#include <string>
#include <cstdlib>
#define WINVER _WIN32_WINNT_WIN10
#include <windows.h>
#include <winioctl.h>
#include <virtdisk.h>
#include <initguid.h>
#pragma comment(lib, "virtdisk.lib")
DEFINE_GUID(VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT, 0xec984aec, 0xa0f9, 0x47e9, 0x90, 0x1f, 0x71, 0x41, 0x5a, 0x66, 0x34, 0x5b);
DEFINE_GUID(VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
int main()
{
HANDLE vhdHandle;
_VIRTUAL_STORAGE_TYPE storageType;
storageType.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN;
storageType.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;
wchar_t path[] = L"C:\\Hyper-V\\Virtual Hard Disks\\Lacazette\\Windows2016.vhdx";
VIRTUAL_DISK_ACCESS_MASK mask = VIRTUAL_DISK_ACCESS_GET_INFO;
PGET_VIRTUAL_DISK_INFO diskInfo;
ULONG diskInfoSize = sizeof(GET_VIRTUAL_DISK_INFO);
std::wcout << "size of diskinfo structure " << diskInfoSize << std::endl;
diskInfo = (PGET_VIRTUAL_DISK_INFO)malloc(diskInfoSize);
if (diskInfo == NULL)
{
std::cout << "Failed to malloc disk info, ret=" << std::endl;
return 0;
}
std::wcout << "Opening Virtual disk " << path << std::endl;
DWORD res = OpenVirtualDisk(&storageType, path,
VIRTUAL_DISK_ACCESS_GET_INFO,
OPEN_VIRTUAL_DISK_FLAG_NO_PARENTS,
NULL,
&vhdHandle);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to open disk, ret=" << res << std::endl;
return 0;
}
diskInfo->Version = GET_VIRTUAL_DISK_INFO_SIZE;
res = GetVirtualDiskInformation(vhdHandle, &diskInfoSize, diskInfo, NULL);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to GET_VIRTUAL_DISK_INFO_SIZE, ret=" << res << std::endl;
}
long physicalSize = diskInfo->Size.PhysicalSize;
long virtualSize = diskInfo->Size.VirtualSize;
long sectorSize = diskInfo->Size.SectorSize;
long blockSize = diskInfo->Size.BlockSize;
std::wcout << "physicalSize :" << physicalSize << std::endl;
std::wcout << "virtualSize :" << virtualSize << std::endl;
std::wcout << "sectorSize :" << sectorSize << std::endl;
std::wcout << "blockSize :" << blockSize << std::endl;
diskInfo->Version = GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
res = GetVirtualDiskInformation(vhdHandle, &diskInfoSize, diskInfo, NULL);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE, ret=" << res << std::endl;
}
std::cout << "\nrct id:" << diskInfo->ChangeTrackingState.MostRecentId << std::endl;
std::cout << "\nQuerying for changed disk areas...\n" << std::endl;
wchar_t rctId[] = L"rctX:c2eb01d9:ccb1:405d:acb6:f0e76d055906:00000001";
ULONG64 byteOffset = 0L;
ULONG64 byteLength = 19327352832;
QUERY_CHANGES_VIRTUAL_DISK_RANGE* changedAreas = NULL;
ULONG rangeCount = 0L;
ULONG64 processedLength = 0L;
res = QueryChangesVirtualDisk(&vhdHandle, rctId, byteOffset, byteLength,
QUERY_CHANGES_VIRTUAL_DISK_FLAG_NONE,
changedAreas, &rangeCount, &processedLength);
if (res != ERROR_SUCCESS)
{
std::cout << "Failed to get chanegd areas, ret=" << res << std::endl;
if (vhdHandle != NULL)
{
CloseHandle(vhdHandle);
std::cout << "closing handle!" <<std::endl;
}
return 0;
}
std::cout << "Total changed areas:" << rangeCount << std::endl;
std::cout << "Total processed length:" << processedLength << std::endl;
if (vhdHandle != NULL)
{
CloseHandle(vhdHandle);
}
return 0;
}
Output of the program:
Screenshot of wmi explorer output.
Here's something that more or less works.. the issue was with the format of the rctid which I was passing to the QueryChangesVirtualDisk API. Should be as in the below sample. I was enclosing it inside the braces {} which was not correct. The below code returns RCT changed blocks successfully
Another observation is that it seems the ChangeTrackingState.MostRecentId which we get from GetVirtualDiskInformation for a offline vhdx is one more than what we initially created while the VM was up.. For example, I created a reference point with rctid: rctX:4abdf273:7e45:4748:85af:78ec4af82ebf:00000000 Now when the vhdx is offline and if I query the ChangeTrackingState.MostRecentId it is giving me this : rctX:4abdf273:7e45:4748:85af:78ec4af82ebf:00000001 which fails the QueryChangesVirtualDisk with invalid rctid error. The below function expects the user to pass the correct rctid externally. Apparently, the Get-VmReferencePoints still lists only the earlier 00000 reference point.. This one (00001) seems to be returned only by the GetVirtualDiskInformation API
Finally, for the other issue of getting access denied with a live VM, it seems we have to set the VIRTUAL_DISK_ACCESS_MASK in OpenVirtualDisk to 0 along with version 3 of OPEN_VIRTUAL_DISK_PARAMETERS as shown below. With this we we are able to query RCT CBT from a live checkpointed VM's base disk. Got clarified from https://github.com/cloudbase/rct-service/issues/1
#include <windows.h>
#include <virtdisk.h>
#include <iostream>
bool QueryRCTData(const std::wstring& file, const std::wstring& rctid)
{
DWORD fRet;
HANDLE hVHD;
VIRTUAL_STORAGE_TYPE vst =
{
VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN,
{0xEC984AEC, 0xA0F9, 0x47e9, { 0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B }}
};
OPEN_VIRTUAL_DISK_PARAMETERS params = { 0 };
params.Version = OPEN_VIRTUAL_DISK_VERSION_3;
DWORD fRet = OpenVirtualDisk(
&vst,
file.c_str(),
(VIRTUAL_DISK_ACCESS_MASK) 0, //VIRTUAL_DISK_ACCESS_ALL, //VIRTUAL_DISK_ACCESS_GET_INFO,
OPEN_VIRTUAL_DISK_FLAG_NONE,
&params,
&hvhd);
if (fRet != ERROR_SUCCESS)
{
std::cout << "OpenVirtualDisk failed " << fRet << "\n";
return false;
}
//query rctid
WCHAR vdinfo[2048];
ZeroMemory(vdinfo, sizeof(vdinfo));
((GET_VIRTUAL_DISK_INFO *)vdinfo)->Version = GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
ULONG vdinfoSize = sizeof(vdinfo);
fRet = GetVirtualDiskInformation(
hVHD,
&vdinfoSize,
(PGET_VIRTUAL_DISK_INFO)vdinfo,
NULL);
if (fRet != ERROR_SUCCESS)
{
std::cout << "GetVirtualDiskInformation GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE failed " << fRet << "\n";
return false;
}
std::wcout << "RCT ID : " << std::wstring(((GET_VIRTUAL_DISK_INFO *)vdinfo)->ChangeTrackingState.MostRecentId) << "\n";
//query disk length
ZeroMemory(vdinfo, sizeof(vdinfo));
((GET_VIRTUAL_DISK_INFO *)vdinfo)->Version = GET_VIRTUAL_DISK_INFO_SIZE;
vdinfoSize = sizeof(vdinfo);
fRet = GetVirtualDiskInformation(
hVHD,
&vdinfoSize,
(PGET_VIRTUAL_DISK_INFO)vdinfo,
NULL);
if (fRet != ERROR_SUCCESS)
{
std::cout << "GetVirtualDiskInformation GET_VIRTUAL_DISK_INFO_SIZE failed " << fRet << "\n";
return false;
}
std::cout << "Disk length : " << ((GET_VIRTUAL_DISK_INFO *)vdinfo)->Size.VirtualSize << "\n";
ULONG RangeCount = 1024;
ULONG64 ProcessedLength = 0;
QUERY_CHANGES_VIRTUAL_DISK_RANGE Ranges[1024] = { 0 };
fRet = QueryChangesVirtualDisk(
hVHD,
rctid.c_str(), //((GET_VIRTUAL_DISK_INFO *)vdinfo)->ChangeTrackingState.MostRecentId,
0,
((GET_VIRTUAL_DISK_INFO *)vdinfo)->Size.VirtualSize,
QUERY_CHANGES_VIRTUAL_DISK_FLAG_NONE,
Ranges,
&RangeCount,
&ProcessedLength);
if (fRet != ERROR_SUCCESS)
{
std::cout << "QueryChangesVirtualDisk failed " << fRet << "\n";
return false;
}
std::cout << "RangeCount : " << RangeCount << "\n";
std::cout << "ProcessedLength : " << ProcessedLength << "\n";
for (int i = 0; i < RangeCount; i++)
{
std::cout << "Range offset : " << Ranges[i].ByteOffset << "\n";
std::cout << "Range length : " << Ranges[i].ByteLength << "\n";
}
CloseHandle(hVHD);
return true;
}
int main(void)
{
QueryRCTData(L"D:\\BACKUP\\INCR\\Virtual Hard Disks\\2019.vhdx", L"rctX:4abdf273:7e45:4748:85af:78ec4af82ebf:00000000");
return 0;
}
#pragma comment(lib, "virtdisk.lib")
Here is my working code for getting changed blocks from offline VHDX.
(most credit goes to Neelabh Mam who posted above)
Hope it might help someone struggling to make RCT work with C++.
BOOLEAN VHDWRAP_CONVENTION CloseVhd(HANDLE hDisk)
{
return CloseHandle(hDisk) == TRUE;
}
HANDLE VHDWRAP_CONVENTION OpenVhdx(PCWSTR path, unsigned mask)
{
DWORD fRet;
HANDLE hVHD;
VIRTUAL_STORAGE_TYPE vst =
{
VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN,
{0xEC984AEC, 0xA0F9, 0x47e9, { 0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B }}
};
OPEN_VIRTUAL_DISK_PARAMETERS params = { 0 };
params.Version = OPEN_VIRTUAL_DISK_VERSION_3;
fRet = OpenVirtualDisk(
&vst,
path, (VIRTUAL_DISK_ACCESS_MASK)mask,
OPEN_VIRTUAL_DISK_FLAG_NONE,
&params,
&hVHD);
g_dwLastError = fRet;
return hVHD;
}
VHDWRAP_API BOOLEAN VHDWRAP_CONVENTION EnableVhdRct(HANDLE hVHD)
{
SET_VIRTUAL_DISK_INFO vdinfo;
vdinfo.Version = SET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
vdinfo.ChangeTrackingEnabled = TRUE;
DWORD fRet = SetVirtualDiskInformation(hVHD, &vdinfo);
g_dwLastError = fRet;
return fRet == 0;
}
VHDWRAP_API BOOLEAN VHDWRAP_CONVENTION DisableVhdRct(HANDLE hVHD)
{
SET_VIRTUAL_DISK_INFO vdinfo;
vdinfo.Version = SET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
vdinfo.ChangeTrackingEnabled = FALSE;
DWORD fRet = SetVirtualDiskInformation(hVHD, &vdinfo);
g_dwLastError = fRet;
return fRet == 0;
}
VHDWRAP_API BOOLEAN VHDWRAP_CONVENTION QueryVhdRct(HANDLE hVHD, LPCWSTR szRctId)
{
//query rctid
WCHAR vdinfo[1024];
ZeroMemory(vdinfo, sizeof(vdinfo));
((GET_VIRTUAL_DISK_INFO*)vdinfo)->Version = GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
ULONG vdinfoSize = sizeof(vdinfo);
DWORD fRet = GetVirtualDiskInformation(
hVHD,
&vdinfoSize,
(PGET_VIRTUAL_DISK_INFO)vdinfo,
NULL);
g_dwLastError = fRet;
if (fRet != ERROR_SUCCESS)
{
std::cout << "GetVirtualDiskInformation GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE failed " << fRet << "\n";
return false;
}
std::wcout << L"RCT status : " << ((((GET_VIRTUAL_DISK_INFO*)vdinfo)->ChangeTrackingState.Enabled) ? L"enabled" : L"disabled") << L"\n";
std::wcout << L"RCT ID : " << std::wstring(((GET_VIRTUAL_DISK_INFO*)vdinfo)->ChangeTrackingState.MostRecentId) << "\n";
std::wcout << L"RCT changes : " << ((((GET_VIRTUAL_DISK_INFO*)vdinfo)->ChangeTrackingState.NewerChanges) ? L"yes": L"no") << "\n";
//query disk length
_GET_VIRTUAL_DISK_INFO sizeInfo;
sizeInfo.Version = GET_VIRTUAL_DISK_INFO_SIZE;
vdinfoSize = sizeof(sizeInfo);
fRet = GetVirtualDiskInformation(
hVHD,
&vdinfoSize,
(PGET_VIRTUAL_DISK_INFO)&sizeInfo,
NULL);
g_dwLastError = fRet;
if (fRet != ERROR_SUCCESS)
{
std::cout << "GetVirtualDiskInformation GET_VIRTUAL_DISK_INFO_SIZE failed " << fRet << "\n";
return FALSE;
}
std::cout << "Disk length : " << sizeInfo.Size.VirtualSize << "\n";
const ULONG MaxRangeCount = 4096*1024;
ULONG RangeCount = MaxRangeCount;
ULONG64 ProcessedLength = 0;
QUERY_CHANGES_VIRTUAL_DISK_RANGE* Ranges = new QUERY_CHANGES_VIRTUAL_DISK_RANGE[MaxRangeCount];
fRet = QueryChangesVirtualDisk(
hVHD,
szRctId?szRctId : ((GET_VIRTUAL_DISK_INFO *)vdinfo)->ChangeTrackingState.MostRecentId,
0,
sizeInfo.Size.VirtualSize,
QUERY_CHANGES_VIRTUAL_DISK_FLAG_NONE,
Ranges,
&RangeCount,
&ProcessedLength);
g_dwLastError = fRet;
if (fRet != ERROR_SUCCESS)
{
delete[] Ranges;
std::cout << "QueryChangesVirtualDisk failed " << fRet << " ranges:" << RangeCount << " len " << ProcessedLength << "\n";
return FALSE;
}
if (MaxRangeCount <= RangeCount || ProcessedLength < sizeInfo.Size.VirtualSize)
{
delete[] Ranges;
std::cout << "Not enough resources to capture all the changes \n";
return FALSE;
}
std::cout << "RangeCount : " << RangeCount << "\n";
std::cout << "ProcessedLength : " << ProcessedLength << "\n";
for (int i = 0; i < RangeCount; i++)
{
std::cout << "Range offset : " << Ranges[i].ByteOffset << "\n";
std::cout << "Range length : " << Ranges[i].ByteLength << "\n";
}
delete[] Ranges;
return TRUE;
}

Basic tampering protection

I'm trying to create a basic program that has tampering protection on the licenseCheck function, however it always says it's correct, even if I nop the whole licenseCheck function in Ollydbg or change and rebuild the code.
I'm following the Surreptitious Software book, and wrote the following program:
#include "stdafx.h"
#define HASH 5131241
void BEGIN() {}
const std::string correctlicense("ABC");
bool licenseCheck() {
std::cout << "Enter license: ";
std::string license;
std::cin >> license;
volatile DWORD d;
// Fingerprint
__asm {
lea ebx, d
mov ebx, 0x050b072b
}
return license.compare(correctlicense) == 0;
}
UINT hash(UINT *beginAddress, UINT *endAddress) {
UINT h = *beginAddress;
for (; beginAddress <= endAddress; beginAddress++) {
h ^= *beginAddress;
}
return h;
}
void END() {}
int main()
{
UINT uHash = hash((UINT*)BEGIN, (UINT*)END);
std::cout << "[Protection checks]" << std::endl;
std::cout << "Tampering: ";
if (uHash != HASH) {
std::cout << "Tampering detected! ( " << uHash << " )" << std::endl;
system("PAUSE");
return 0;
}
else {
std::cout << "Correct" << std::endl;
}
if (licenseCheck()) {
std::cout << "Correct!" << std::endl;
}
else {
std::cout << "Failed!" << std::endl;
}
system("PAUSE");
return 0;
}
The program basically 'hashes' the code between the BEGIN function and END function, but it doesn't seem to work. The hash is always correct even after tampering.
I'm using Windows 7 and Visual studio 2017 the build/run the program.

Not sure where the segmentation fault is

I'm getting problem with segmentation fault when trying to compile a C++ program, but not sure where the problem lies. I suspect that the problem lies with the .find() ..... could it be the iterator operator < and == which are the comparators for find() that is the issue? I hope that someone can point out to me where they think the problem lies.
The following is part of test01.cpp, where I run it to test the code and use print statements to find out where the problem is:
bool confirmEverythingMatches(const btree<long>& testContainer, const set<long>& stableContainer) {
cout << "Confirms the btree and the set "
"contain exactly the same values..." << endl;
for (long i = kMinInteger; i <= kMaxInteger; i++) {
cout << "Start of for-loop to find iterator for comparisons..." << endl;
if (stableContainer.find(i) != stableContainer.end()) {
cout << "can find i (" << i << ") in stableContainer!" << endl;
} else {
cout << "cannot find i (" << i << ") in stableContainer!" << endl;
}
cout << "In between finding i in stable and testContainers..." << endl;
if (testContainer.find(i) != testContainer.end()) {
cout << "can find i (" << i << ") in testContainer!" << endl;
} else {
cout << "cannot find i (" << i << ") in testContainer!" << endl;
}
cout << "Before assigning the find to boolean variables..." << endl;
bool foundInTree = (testContainer.find(i) != testContainer.end());
cout << "testContainer.find(i) != testContainer.end()" << endl;
bool foundInSet = (stableContainer.find(i) != stableContainer.end());
cout << "stableContainer.find(i) != stableContainer.end()" << endl;
if (foundInTree != foundInSet) {
cout << "- btree and set don't contain the same data!" << endl;
cout << "Mismatch at element: " << i << endl;
return false;
} else {cout << "foundInTree == foundInSet!!!" << i << endl;}
}
cout << "- btree checks out just fine." << endl;
return true;
}
} // namespace close
/**
* Codes for testing various bits and pieces. Most of the code is commented out
* you should uncomment it as appropriate.
**/
int main(void) {
// initialise random number generator with 'random' seed
initRandom();
cout << "after initRandom().." << endl;
// insert lots of random numbers and compare with a known correct container
btree<long> testContainer(99);
cout << "after specifying max node elements in testContainer.." << endl;
set<long> stableContainer;
cout << "after constructing stableContainer.." << endl;
insertRandomNumbers(testContainer, stableContainer, 1000000);
cout << "after inserting random numbers into testContainer and for success inserts, also into stableContainer.." << endl;
btree<long> btcpy = testContainer;
cout << "after copy assigning a copy of testContainer to btcopy.." << endl;
confirmEverythingMatches(btcpy, stableContainer);
cout << "after confirming everything internally matches between testContainer and stableContainer.." << endl;
return 0;
}
The output I get when running the program (No problem when compiling) is this:
Confirms the btree and the set contain exactly the same values...
Start of for-loop to find iterator for comparisons...
cannot find i (1000000) in stableContainer!
In between finding i in stable and testContainers...
ASAN:DEADLYSIGNAL
=================================================================
==7345==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000018 (pc 0x000108d132a8 bp 0x000000000000 sp 0x7fff56eee6f0 T0)
#0 0x108d132a7 in btree<long>::find(long const&) const (test01+0x1000022a7)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (test01+0x1000022a7) in btree<long>::find(long const&) const
==7345==ABORTING
Abort trap: 6
I also got this error when I tried to run it on another machine:
==29936==ERROR: AddressSanitizer failed to allocate 0x200000 (2097152) bytes of SizeClassAllocator32: 12
I found that when it goes into the find(), it will have the segmentation fault:
/**
* Identical in functionality to the non-const version of find,
* save the fact that what's pointed to by the returned iterator
* is deemed as const and immutable.
*
* #param elem the client element we are trying to match.
* #return an iterator to the matching element, or whatever the
* const end() returns if no such match was ever found.
*/
template<typename T> typename btree<T>::const_iterator
btree<T>::find(const T& elem) const {
std::cout << "CONST ITERATOR'S FIND" << std::endl;
Node *tmp_ = root_;
std::cout << "1" << std::endl;
while(true) {
std::cout << "2" << std::endl;
size_t i;
std::cout << "3" << std::endl;
// go through all elements from root to tail
for (i = 0; i < tmp_->__occupied_size_; ++i) {
std::cout << "4" << std::endl;
if (tmp_->__elem_[i] == elem) {
std::cout << "5" << std::endl;
// find the elem, return an iterator
return const_iterator(tmp_, i, this);
std::cout << "6" << std::endl;
} else if (tmp_->__elem_[i] > elem) {
std::cout << "7" << std::endl;
// elem is not in current Node, go to descendants
// for the elem.
if (tmp_->__descendants_ == nullptr) {
std::cout << "8" << std::endl;
return cend();
std::cout << "9" << std::endl;
} else {
std::cout << "10" << std::endl;
tmp_ = tmp_->__descendants_[i];
std::cout << "11" << std::endl;
break;
}
}
}
// handling boundaries cases
if (i == tmp_->__occupied_size_) {
std::cout << "12" << std::endl;
if (tmp_->__descendants_[i] == nullptr) {
std::cout << "13" << std::endl;
return cend();
std::cout << "14" << std::endl;
} else {
std::cout << "15" << std::endl;
tmp_ = tmp_->__descendants_[i];
}
}
}
}
The print statements for this find is:
CONST ITERATOR'S FIND
1
2
3
4
4
7
10
11
2
3
4
7
10
11
ASAN:DEADLYSIGNAL
Ok, so based on the implementation of this find function, I think the problem might be located in
if (tmp_->__descendants_ == nullptr) {
std::cout << "8" << std::endl;
return cend();
std::cout << "9" << std::endl;
} else {
std::cout << "10" << std::endl;
tmp_ = tmp_->__descendants_[i];
std::cout << "11" << std::endl;
break;
}
and then
// handling boundaries cases
if (i == tmp_->__occupied_size_) {
std::cout << "12" << std::endl;
if (tmp_->__descendants_[i] == nullptr) {
std::cout << "13" << std::endl;
return cend();
std::cout << "14" << std::endl;
} else {
std::cout << "15" << std::endl;
tmp_ = tmp_->__descendants_[i];
}
}
So, You are checking if tmp->__descendants_ is not null. If it is not, then you set tmp_ = tmp_->descendants_[i];
Note: you are just checking __descendants_ pointer to be null or not, you are not checking the __descendants_ [i] if it is null!
What if the tmp->__descendants_[i] is null (or gets out of the descendants array)?
If that value is null, then tmp_->occupied_size_ might give you segfault.
Note2: For some reason you are using same index "i" for iterating through __elem_ and __descendants_. I am not sure, how descendants are created, but it might be also a problem here.
This is why debuggers exist. Run your program in the debugger, let the program fail, and then the debugger will tell you where and why it's gone wrong.
It looks like you've got potentially a lot of code to trawl through, which no one here will really want to do as it's not a concise question.
Good luck!

Win API ReadProcessMemory at base address of DLL returning unexpected data

I'm trying to read the contents of a DLL from memory for some academic research. Specifically, the NTDSA.DLL library for the purpose of mutating specific instructions to simulate programming errors to force the system to fail. The failure will then be recorded to train machine learning algorithms to predict future failures (this is an attempt to generalize previously published research seen here).
I'm getting what I believe to be the base address in virtual memory of the lsass.exe process (which loads the target DLL) through the process outlined here. I'm then calling ReadProcessMemory with an allocated buffer and the handle to lsass obtained by calling OpenProcess with 'PROCESS_ALL_ACCESS' set. The ReadProcessMemory returns with error code 299 80% of the time (partial read) with zero bytes read. My assumption is that the area I'm trying to access is in use when the call is made. Fortunately, it will occasionally return the number of bytes I'm requesting. Unfortunately, the data returned does not match what is on disk when compared to the static DLL in the System32 directory.
So the question is, is ReadProcessMemory doing something funny with the address that I give it, or is my virtual address wrong? Is there another way to figure out where that DLL gets loaded into memory? Any thoughts? Any help or suggestions would be greatly appreciated.
Adding Code:
// FaultInjection.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <windows.h>
#include <psapi.h>
#include <string>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <io.h>
#include <tchar.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[]) {
// Declarations
int pid = 0;
__int64* start_addr;
DWORD size_of_ntdsa;
DWORD aProcesses[1024], cbNeeded, cProcesses;
TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
HMODULE hmods[1024];
unsigned int i;
// Get All pids
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)){
cout << "Failed to get all PIDs: " << GetLastError() << endl;
return -1;
}
// Find pid for lsass.exe
cProcesses = cbNeeded / sizeof(DWORD);
for (i = 0; i < cProcesses; i++) {
if (aProcesses[i] != 0) {
HANDLE hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, aProcesses[i]);
if (hProc != NULL) {
HMODULE hMod;
DWORD cbNeededMod;
if (EnumProcessModules(hProc, &hMod, sizeof(hMod), &cbNeededMod)) {
GetModuleBaseName(hProc, hMod, szProcessName, sizeof(szProcessName) / sizeof(TCHAR));
}
if (wstring(szProcessName).find(L"lsass.exe") != string::npos) {
pid = aProcesses[i];
}
CloseHandle(hProc);
}
}
}
cout << "lsass pid: " << pid << endl;
HANDLE h_lsass = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!h_lsass) {
cout << "Failed to open process (are you root?): " << GetLastError() << endl;
return -1;
}
// Get Process Image File Name
char filename[MAX_PATH];
if (GetProcessImageFileName(h_lsass, (LPTSTR)&filename, MAX_PATH) == 0) {
cout << "Failed to get image file name: " << GetLastError() << endl;
CloseHandle(h_lsass);
return -1;
}
// Enumerate modules within process
if (EnumProcessModules(h_lsass, hmods, sizeof(hmods), &cbNeeded)) {
for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) {
TCHAR szModName[MAX_PATH];
if (GetModuleFileNameEx(h_lsass, hmods[i], szModName, sizeof(szModName) / sizeof(TCHAR))) {
if (wstring(szModName).find(L"NTDSA.dll") != string::npos) {
_tprintf(TEXT("%s\n"), szModName);
MODULEINFO lModInfo = { 0 };
if (GetModuleInformation(h_lsass, hmods[i], &lModInfo, sizeof(lModInfo))){
cout << "\t Base Addr: " << lModInfo.lpBaseOfDll << endl;
cout << "\t Entry Point: " << lModInfo.EntryPoint << endl;
cout << "\t Size of image: " << lModInfo.SizeOfImage << endl;
start_addr = (__int64*)lModInfo.lpBaseOfDll;
size_of_ntdsa = lModInfo.SizeOfImage;
}
else {
cout << "Failed to Print enumerated list of modules: " << GetLastError() << endl;
}
}
} else {
cout << "Failed to Print enumerated list of modules: " << GetLastError() << endl;
}
}
}
else {
cout << "Failed to enum the modules: " << GetLastError() << endl;
}
// Ready to continue?
string cont = "";
cout << "Continue? [Y|n]: ";
getline(cin, cont);
if (cont.find("n") != string::npos || cont.find("N") != string::npos) {
CloseHandle(h_lsass);
return 0;
}
void* buf = malloc(size_of_ntdsa);
if (!buf) {
cout << "Failed to allocate space for memory contents: " << GetLastError() << endl;
CloseHandle(h_lsass);
return -1;
}
SIZE_T num_bytes_read = 0;
int count = 0;
if (ReadProcessMemory(h_lsass, &start_addr, buf, size_of_ntdsa, &num_bytes_read) != 0) {
cout << "Read success. Got " << num_bytes_read << " bytes: " << endl;
} else {
int error_code = GetLastError();
if (error_code == 299) {
cout << "Partial read. Got " << num_bytes_read << " bytes: " << endl;
} else {
cout << "Failed to read memory: " << GetLastError() << endl;
CloseHandle(h_lsass);
free(buf);
return -1;
}
}
if (num_bytes_read > 0) {
FILE *fp;
fopen_s(&fp, "C:\\ntdsa_new.dll", "w");
SIZE_T bytes_written = 0;
while (bytes_written < num_bytes_read) {
bytes_written += fwrite(buf, 1, num_bytes_read, fp);
}
fclose(fp);
cout << "Wrote " << bytes_written << " bytes." << endl;
}
CloseHandle(h_lsass);
free(buf);
return 0;
}
Code works as described minus my amateur mistake of sending the address of the variable I was using to store the address of the location in virtual memory of the target application. In above code, changed:
if (ReadProcessMemory(h_lsass, &start_addr, buf, size_of_ntdsa, &num_bytes_read) != 0) {
to
if (ReadProcessMemory(h_lsass, start_addr, buf, size_of_ntdsa, &num_bytes_read) != 0) {
Works like a charm. Thank you ssbssa for pointing out mistake, sorry for wasting anyone's time.

C++ ReadProcessMemory buffer always displays 0

my &pTemp
So I think I'm not understanding this quite well. If I'm not mistaken, the pointer value should be stored in pTemp, right?. So, if the base pointer is 0x00001A, shouldn't pTemp display the same thing? I'm really new to C++ and any help would be appreciated!
DWORD pointer = baseAddress;
DWORD pTemp;
DWORD pointerAddress;
cout << "Base Address: " << (DWORD*) pointer << endl;
for (int i = 0; i < PointerLevel; i++)
{
if (i == 0)
{
ReadProcessMemory(handle, (LPVOID)pointer, &pTemp, sizeof(4), NULL);
cout << "pTemp: " << pTemp << endl;
Try this:
void * src_addr = reinterpret_cast<void *>(baseAddress);
std::size_t n;
if (ReadProcessMemory(handle, src_addr, &pTemp, sizeof pTemp, &n))
{
if (n == sizeof pTemp)
{
std::cout << "Success: pTemp = " << pTemp << "\n";
}
else
{
std::cout << "We only read " << n << " bytes, not the expected "
<< sizeof pTemp << " bytes.\n";
}
}
else
{
std::cout << "Failed to read process memory.\n";
}