Blackbone is located here:
https://github.com/DarthTon/Blackbone
Now what I would like to try to achieve is to read process memory using the aforementioned library.
I have used the pattern scan method to obtain an address in memory which I will later use in the reading process, however I'm getting a bit stuck on whether how I should read the data stored at the Output buffer that the read method is using.
The Read method is structured here:
https://github.com/DarthTon/Blackbone/blob/master/src/BlackBone/Process/ProcessMemory.h#L57
And I'm following exactly the same approach taken in the patternscan example provided at:
https://github.com/DarthTon/Blackbone/blob/master/src/TestApp/PatternTest.cpp
Just with a little slightly difference:
void FindKeys()
{
Process p;
std::vector<DWORD> procs;
std::vector<ptr_t> results;
ptr_t dwAddress;
size_t dwSize;
PVOID pResult;
bool handleHoles = true;
Process::EnumByName(L"Notepad++.exe", procs);
if (!procs.empty())
{
p.Attach(procs.front());
auto pMainMod = p.modules().GetMainModule();
// Initialize patterns
PatternSearch ps1{ 0x33, 0xC5, 0x89 };
// Scan all allocated process memory
std::wcout << L"[+] Searching for Pattern Scan...\n";
ps1.SearchRemoteWhole(p, false, 0, results);
std::wcout << L"[+] Found at Address: [0x";
std::wcout << std::hex << results[0];
std::wcout << L"]!\n";
dwAddress = results[0];
dwSize = 0x10;
p.memory().Read(dwAddress, dwSize, pResult, handleHoles);
results.clear();
}
else
std::wcout << L"Can't find Notepad++.exe, aborting\n\n";
}
My question comes from failing to read pResult, how could I successfully read from it, specifically, I would like to read it as an array of bytes.
Thanks in advance for any further help you guys provide me, it will be deeply appreciated!
Alright guys, here is it, fairly simple! and I was over complicating myself.
What I did was to create another variable type BYTE (unsigned char byte) named pResultBytes and then use memcpy(&pResultBytes, pResult, dwSize); where pResult is the output buffer from the Read() method and dwSize is the number of bytes to copy to the new variable.
Next I just started iterating through the pResultBytes variable byte by byte and doing the relative conversions to make a hex string and ultimately read it.
Woops almost for got to mention, I also initialized pResult to a new UCHAR[dwSize]; as well, so it eventually has the proper space required for the memcpy.
That's it!
Cheers!
Related
I try to use the following code from kernel mode in a driver:
NTSTATUS NTAPI MmCopyVirtualMemory
(
PEPROCESS SourceProcess,
PVOID SourceAddress,
PEPROCESS TargetProcess,
PVOID TargetAddress,
SIZE_T BufferSize,
KPROCESSOR_MODE PreviousMode,
PSIZE_T ReturnSize
);
I use it in the following way:
PEPROCESS process;
NTSTATUS status;
unsigned int readValue;
// get notepad.exe process -> Notepad is opened already and this is the ID from Task Mgr
status = PsLookupProcessByProcessId((HANDLE)7252, &process);
if (!NT_SUCCESS(status))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "\n\n ## Lookup By Id failed. ##\n\n");
if (status == STATUS_INVALID_CID)
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "\n\n ## Id could not be found. ##\n\n");
}
goto Exit;
}
SIZE_T cbBytesReturned;
status = MmCopyVirtualMemory(process, 0x00, PsGetCurrentProcess(), &readValue, sizeof(unsigned int), KernelMode, &cbBytesReturned);
if (!NT_SUCCESS(status))
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "\n\n ## MemCopy failed. ##\n\n");
}
else
{
DbgPrintEx(DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, "\n\n ## MemCopy DONE ##\n\n");
}
ObfDereferenceObject(process);
Currently this fails. I assumed that 0x00 points to the first byte of memory of the process I am reading from. A I wrong or is that relative which means process + 0x00 is the first memory location ?
I am not sure why you think your code is going to work, your input values for MmCopyVirtualMemory are not correct.
You're passing a NULL pointer for the second parameter. How is the Windows Kernel supposed to know where the memory you'd like to copy from the SourceProcess is present if you don't give it a valid address?
You're passing the pointer address to a local variable as the fourth parameter, yet the fourth parameter is supposed to be a pointer address which is valid under the process you're targeting (the third parameter). The pointer address used for the fourth parameter is supposed to be where you'd like to put the memory copied from the SourceAddress (within the virtual memory of SourceProcess) within the TargetProcess.
For the fifth parameter, you're passing the size of an unsigned int? This is also incorrect.
I believe the fifth parameter (BufferSize) should be the length of how much memory you'd like to copy from SourceAddress into TargetAddress. If this is the case, make sure that there is enough room at TargetAddress - take this with a grain of salt.
I suggest you take a look at the function prototype which you shared in your original post and re-check your code, and try again, taking on-board my comments here and after some more research on the routine.
Remember though, MmCopyVirtualMemory is not officially documented and you'll be taking a risk by using it in any production-level source code. I recommend strongly that you re-consider your options if this isn't just an educational experiment, because stable and documented code is generally an important thing.
I'm quite afraid the question is really, really simple, but even thou I'm starting to grip the idea of pointers, hints from experienced users shorten the time I need to spend on it to understand everything. Ive got a simple example, I won't go into details what its supposed to do later on, because I think my mistake is something very basic. I'm getting:
Exception thrown: read access violation.
_First was 0x815110.
When executing this code:
#include <Windows.h>
#include <iostream>
#include "Header.h"
#pragma comment(linker, "/SECTION:.data,RWE")
using std::cout;
using std::endl;
int main() {
DWORD dwProcessID = 0;
cout << "Looking for game process..." << endl;
while (dwProcessID == 0) {
dwProcessID = GetProcessID(L"PathOfExile.exe");
Sleep(100);
}
std::cout << "Game Client found" << std::endl;
printf("dwProcessID = %p\n", dwProcessID);
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessID);
MODULEENTRY32 module;
module.dwSize = sizeof(MODULEENTRY32);
Module32First(snapshot, &module);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, dwProcessID);
HANDLE hToken = NULL;
if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hToken))
printf("Failed to open access token\n");
if (!SetPrivilege(hToken, SE_DEBUG_NAME, TRUE))
printf("Failed to set debug privilege\n");
printf("PoE base address = %p\n", module.modBaseAddr);
BYTE jmp[] = "\xBA\x00\x00\x80\x3F\x89\x10\x89\x16\xE9\x00\x00\x00\x00";
BYTE *dwMaphack = (BYTE*)(module.modBaseAddr + 0x4D5110);
cout << dwMaphack << endl;
*(DWORD*)&jmp[10] = (DWORD)(dwMaphack - jmp) - 6;
DWORD dwOldProt;
VirtualProtectEx(hProcess, (LPVOID)dwMaphack, 8, PAGE_EXECUTE_READWRITE, &dwOldProt);
// tbc
while (1) {
}
return 0;
}
The open process methods and other basic stuff are in the header and they do work fine, what I don't get is why when I change the byte pointer BYTE *dwMaphack to DWORD *dwMaphack, there's no longer an access violation error?
I'm trying to base my code on an outdated code of someones that no longer works, so the reason for doing these operations is only partially known for me, I know what it's supposed to do in programming terms, but I don't know the effect in the game, yet. I don't think it's important in terms of the error I'm getting anyway. Thanks in advance for the answers!
BYTE is an alias for unsigned char.
std::cout has an overloaded operator<< that accepts an unsigned char* pointer as input and prints it as a character string (as stated by Harry Johnston, https://stackoverflow.com/a/41538200/7376565). So it crashes when it tries to access memory it does not have access to.
std::cout does not have an operator<< overload for DWORD* (aka unsigned long*), but it does have one for void*, so any non-character pointer will print just the value of the pointer itself. When you change dwMaphack to DWORD*, operator<< doesn't try to access the memory that dwMaphack points to, so no access violation occurs.
Here's your problem:
cout << dwMaphack << endl;
This is attempting to print the value that dwMaphack points to, not the value of the pointer. Since the pointer is only valid in the remote process, attempting to dereference it results in an access violation.
This works:
cout << (DWORD_PTR)dwMaphack << endl;
I thought I read the documentation correctly over at MSDN but apparently I didn't? I am not entirely sure what the heck I'm doing wrong and I'm ready to pull my hair out.
The documentation for the EVENTLOGRECORD structure provides the offset to the SID
https://msdn.microsoft.com/en-us/library/windows/desktop/aa363646(v=vs.85).aspx
UserSidOffset
The offset of the security identifier (SID) within this event log record. To obtain the user name for this SID, use the LookupAccountSid function.
Then to convert this sid, we use the LookupAccountSid() API.
https://msdn.microsoft.com/en-us/library/windows/desktop/aa379166(v=vs.85).aspx
lpSid [in]
A pointer to the SID to look up.
I've searched endlessly and found examples that look very similar to my implementation but gave me the same result. I'm rusty with the Windows API, so I wouldn't be surprised if I am overlooking the issue.
And finally, here is my code:
size_t BytesRemaining = 0;
while (BytesRemaining < BytesInBuffer)
{
EVENTLOGRECORD *Record = reinterpret_cast<EVENTLOGRECORD *>(buffer + BytesRemaining);
char UsernameBuffer[256], DomainBuffer[256];
DWORD UsernameBufferSize = 256, DomainBufferSize = 256;
SID_NAME_USE SidType;
PSID SID = (PSID)((LPBYTE)Record + Record->UserSidOffset);
if (!LookupAccountSid(NULL, SID, UsernameBuffer, &UsernameBufferSize, DomainBuffer, &DomainBufferSize, &SidType))
{
std::cout << "Failed reading SID (" << SID << "): " << GetLastErrorMessage().c_str();
}
else {
std::cout << "I didn't shit on the SID.\n";
}
BytesRemaining += Record->Length;
}
bytesInBuffer = 0;
Edit
After doing some debugging, I discovered that the StringsOffset and UserSidOffset contain the same value. So it looks like the offsets are pointing incorrectly... Which is why I am not able to pass a valid SID to the API.
Anyone?
cchName [in, out]
On input, specifies the size, in TCHARs, of the lpName buffer. If the function fails because the buffer is too small or if cchName is zero, cchName receives the required buffer size, including the terminating null character.
cchReferencedDomainName [in, out]
On input, specifies the size, in TCHARs, of the lpReferencedDomainName buffer. If the function fails because the buffer is too small or if cchReferencedDomainName is zero, cchReferencedDomainName receives the required buffer size, including the terminating null character.
You need to assign the array sizes to UsernameBufferSize and DomainBufferSize before calling LookupAccountSid(). Either that, or set them to zero and then dynamically allocate UsernameBuffer and DomainBuffer, then call LookupAccountSid() again.
In some code I use the Win32 RegGetValue() API to read a string from the registry.
I call the aforementioned API twice:
The purpose of the first call is to get the proper size to allocate a destination buffer for the string.
The second call reads the string from the registry into that buffer.
What is odd is that I found that RegGetValue() returns different size values between the two calls.
In particular, the size value returned in the second call is two bytes (equivalent to one wchar_t) less than the first call.
It's worth noting that the size value compatible with the actual string length is the value returned by the second call (this corresponds to the actual string length, including the terminating NUL).
But I don't understand why the first call returns a size two bytes (one wchar_t) bigger than that.
A screenshot of program output and Win32 C++ compilable repro code are attached.
Repro Source Code
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void PrintSize(const char* const message, const DWORD sizeBytes)
{
cout << message << ": " << sizeBytes << " bytes ("
<< (sizeBytes/sizeof(wchar_t)) << " wchar_t's)\n";
}
int main()
{
const HKEY key = HKEY_LOCAL_MACHINE;
const wchar_t* const subKey = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion";
const wchar_t* const valueName = L"CommonFilesDir";
//
// Get string size
//
DWORD keyType = 0;
DWORD dataSize = 0;
const DWORD flags = RRF_RT_REG_SZ;
LONG result = ::RegGetValue(
key,
subKey,
valueName,
flags,
&keyType,
nullptr,
&dataSize);
if (result != ERROR_SUCCESS)
{
cout << "Error: " << result << '\n';
return 1;
}
PrintSize("1st call size", dataSize);
const DWORD dataSize1 = dataSize; // store for later use
//
// Allocate buffer and read string into it
//
vector<wchar_t> buffer(dataSize / sizeof(wchar_t));
result = ::RegGetValue(
key,
subKey,
valueName,
flags,
nullptr,
&buffer[0],
&dataSize);
if (result != ERROR_SUCCESS)
{
cout << "Error: " << result << '\n';
return 1;
}
PrintSize("2nd call size", dataSize);
const wstring text(buffer.data());
cout << "Read string:\n";
wcout << text << '\n';
wcout << wstring(dataSize/sizeof(wchar_t), L'*') << " <-- 2nd call size\n";
wcout << wstring(dataSize1/sizeof(wchar_t), L'-') << " <-- 1st call size\n";
}
Operating System: Windows 7 64-bit with SP1
EDIT
Some confusion seems to be arisen by the particular registry key I happened to read in the sample repro code.
So, let me clarify that I read that key from the registry just as a test. This is not production code, and I'm not interested in that particular key. Feel free to add a simple test key to the registry with some test string value.
Sorry for the confusion.
RegGetValue() is safer than RegQueryValueEx() because it artificially adds a null terminator to the output of a string value if it does not already have a null terminator.
The first call returns the data size plus room for an extra null terminator in case the actual data is not already null terminated. I suspect RegGetValue() does not look at the real data at this stage, it just does an unconditional data size + sizeof(wchar_t) to be safe.
(36 * sizeof(wchar_t)) + (1 * sizeof(wchar_t)) = 74
The second call returns the real size of the actual data that was read. That size would include the extra null terminator only if one had to be artificially added. In this case, your data has 35 characters in the path, and a real null terminator present (which well-behaved apps are supposed to do), thus the extra null terminator did not need to be added.
((35+1) * sizeof(wchar_t)) + (0 * sizeof(wchar_t)) = 72
Now, with that said, you really should not be reading from the Registry directly to get the CommonFilesDir path (or any other system path) in the first place. You should be using SHGetFolderPath(CSIDL_PROGRAM_FILES_COMMON) or SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon) instead. Let the Shell deal with the Registry for you. This is consistent across Windows versions, as Registry settings are subject to be moved around from one version to another, as well as accounting for per-user paths vs system-global paths. These are the main reasons why the CSIDL API was introduced in the first place.
I am trying to get the entire raw header into a file but everytime I attempt to write the contents I get a file full of ÌÌÌÌÌÌÌÌÌÌÌ. What am I doing wrong?
DWORD CTryISAPIFilter::OnPreprocHeaders(CHttpFilterContext* httpContext,
PHTTP_FILTER_PREPROC_HEADERS headerInformation)
{
char buffer[4096];
DWORD bufferSize = sizeof(buffer);
BOOL HeaderBoolean = headerInformation->GetHeader(httpContext->m_pFC, "ALL_RAW", buffer, &bufferSize);
char * ptrIn = (char *) buffer;
std::string postData2 = ptrIn;
char * outputString = new char[4096];
int i = 0;
for(i=0;i<4096;i++){
outputString[i] = postData2[i];
}
outputString[i+1] = NULL;
std::ofstream outfile ("D:\\WebSites\\wwwroot\\test.txt",std::ios::app);
outfile << outputString << std::endl;
outfile.close();
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
Is headerInformation->GetHeader() returning success?
If so, how much is it actually writing into buffer (presumably it tells you this in a value it places in bufferSize)
I suspect that GetHeader() is failing, and nothing is being written to buffer because:
you're getting all "ÌÌÌÌÌÌÌÌÌÌÌ" characters (which is what the debug builds of VC will set uninitialized memory to), and
you're not getting an exception thrown when you index postData2 well past what should usually be the end of the string (in most cases anyway). So there's apparently no '\0' terminator in buffer (which GetHeader() will write if it succeeds).
You need to check for this failure and examine GetLastError() to get more information on what the failure is.
Update: Your buffer might not be large enough. See http://msdn.microsoft.com/en-us/magazine/cc163939.aspx for how to appropriately size the buffer.
Update 2: It's been a while since I've done web stuff, but isn't "ALL_RAW" a CGI-style server environment variable rather than a header? Shouldn't you retrieve this using GetServerVariable() instead of GetHeader()?