Windows 7 DLL Injection - c

I am trying to inject a dll into an existing process. I am trying to use the CreateRemoteThread LoadLibrary way. I understand how it works, but I cannot figure out why CreateRemoteThread is returning null (failing)... I am on Windows 7 so this may be the reason, but I don't know for sure if it is.. Perhaps I need to set privaleges? My code is below:
#define DLL_NAME "message.dll"
void main()
{
InjectDLL(1288, DLL_NAME);
}
BOOL InjectDLL(DWORD dwProcessId, LPCSTR lpszDLLPath)
{
HANDLE hProcess, hThread;
LPVOID lpBaseAddr, lpFuncAddr;
DWORD dwMemSize, dwExitCode;
BOOL bSuccess = FALSE;
HMODULE hUserDLL;
if((hProcess = OpenProcess(PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION
|PROCESS_VM_WRITE|PROCESS_VM_READ, FALSE, dwProcessId)))
{
dwMemSize = lstrlen(lpszDLLPath) + 1;
if(lpBaseAddr = VirtualAllocEx(hProcess, NULL, dwMemSize, MEM_COMMIT, PAGE_READWRITE))
{
if(WriteProcessMemory(hProcess, lpBaseAddr, lpszDLLPath, dwMemSize, NULL))
{
if(hUserDLL = LoadLibrary(TEXT("kernel32.dll")))
{
if(lpFuncAddr = GetProcAddress(hUserDLL, TEXT("LoadLibraryA")))
{
if(hThread = CreateRemoteThread(hProcess, NULL, 0, lpFuncAddr, lpBaseAddr, 0, NULL))
{
WaitForSingleObject(hThread, INFINITE);
if(GetExitCodeThread(hThread, &dwExitCode)) {
bSuccess = (dwExitCode != 0) ? TRUE : FALSE;
}
CloseHandle(hThread);
}
}
FreeLibrary(hUserDLL);
}
}
VirtualFreeEx(hProcess, lpBaseAddr, 0, MEM_RELEASE);
}
CloseHandle(hProcess);
}
return bSuccess;
}

yes you need privileges before you open the precess, here's the code:
int GimmePrivileges(){
HANDLE Token;
TOKEN_PRIVILEGES tp;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &Token)
{
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid); tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(Token, 0, &tp, sizeof(tp), NULL, NULL);
}
}
An other thing... this code is confusing!!! you need to synthesize!

Related

program crashes on calling RmShutdown()

I'm experiencing a strange issue with the Restart Manager API.
I'm trying to debug a runtime error that is causing my program to crash in the middle of execution.
I have created a logging system that writes a simple log text file during the course of execution. I tried to debug the program, but it doesn't appear in my system, and the program crashes on calling RmShutdown().
This function crashes on specific files, and sometimes it doesn't appear. For example, most times it appears on C:\Users\Administrator\ntuser.dat.LOG1.
I know I shouldn't kill a system process, but it's a test when the crash happens. Does killing a process that has a handle of file make my program crash?
What could possibly be wrong here? Why would RmShutdown() fail?
BOOL KillFileOwner(__in LPCWSTR PathName)
{
BOOL Result = FALSE;
DWORD dwSession = 0xFFFFFFFF; // Invalid handle value
DWORD ret = 0;
WCHAR szSessionKey[CCH_RM_SESSION_KEY + 1] = { 0 };
if (RmStartSession(&dwSession, 0, szSessionKey) == ERROR_SUCCESS)
{
if (RmRegisterResources(dwSession, 1, &PathName, 0, NULL, 0, NULL) == ERROR_SUCCESS)
{
DWORD dwReason = 0x0;
UINT nProcInfoNeeded = 0;
UINT nProcInfo = 0;
PRM_PROCESS_INFO ProcessInfo = NULL;
// RtlSecureZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
ret = (DWORD)RmGetList(dwSession, &nProcInfoNeeded, &nProcInfo, NULL, &dwReason);
if (ret != ERROR_MORE_DATA || !nProcInfoNeeded) {
RmEndSession(dwSession);
return FALSE;
}
ProcessInfo = (PRM_PROCESS_INFO)calloc(nProcInfoNeeded, sizeof(RM_PROCESS_INFO));
if (!ProcessInfo) {
RmEndSession(dwSession);
return FALSE;
}
nProcInfo = nProcInfoNeeded;
ret = (DWORD)RmGetList(dwSession, &nProcInfoNeeded, &nProcInfo, ProcessInfo, &dwReason);
if (ret != ERROR_SUCCESS || !nProcInfoNeeded) {
free(ProcessInfo);
RmEndSession(dwSession);
return FALSE;
}
DWORD ProcessId = (DWORD)GetProcessId(GetCurrentProcess());
if (!ProcessId) {
free(ProcessInfo);
RmEndSession(dwSession);
return FALSE;
}
for (UINT i = 0; i < nProcInfo; i++) {
if (ProcessInfo[i].Process.dwProcessId == ProcessId) {
free(ProcessInfo);
RmEndSession(dwSession);
return FALSE;
}
}
Result = (RmShutdown(dwSession, RmForceShutdown, NULL) == ERROR_SUCCESS);
free(ProcessInfo);
}
RmEndSession(dwSession);
}
return Result;
}

strtok_s return incorrect data inside windbg

(Hello Everyone) I have some problem with strtok_s. I wrote this code(x64).
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
BOOL TestMD5(CONST WCHAR* MD5_DATABASE_FILE)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD FileSize = 0;
DWORD dwReaded = 0;
PBYTE pData = NULL;
BOOL bRead = FALSE;
PCHAR token_string = NULL;
PCHAR context = NULL;
CONST PCHAR delimeter = "\r\n";
hFile = CreateFileW(
MD5_DATABASE_FILE,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
wprintf(L"Can't open md5 database file: ");
return FALSE;
}
FileSize = GetFileSize(hFile, NULL);
if (FileSize == 0 || FileSize == INVALID_FILE_SIZE)
{
CloseHandle(hFile);
return FALSE;
}
pData = (PBYTE)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (SIZE_T)FileSize);
if (pData == NULL)
{
CloseHandle(hFile);
return FALSE;
}
bRead = ReadFile(hFile, pData, FileSize, &dwReaded, NULL);
if (bRead != TRUE || dwReaded != FileSize)
{
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return FALSE;
}
token_string = (PCHAR)strtok_s(pData, delimeter, &context);
if (token_string == NULL)
{
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return FALSE;
}
do {
printf("%s\n", token_string);
} while (token_string = (PCHAR)strtok_s(NULL, delimeter, &context));
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return TRUE;
}
int main(void)
{
WCHAR* MD5_DATABASE_FILE = L"c:\\md5.txt";
TestMD5(MD5_DATABASE_FILE);
}
When I run exe this gives me a incorrect data. Content of md5.txt (DC288E0B39EA16B4E9455F82FF265A67:1213:TestDBG + (\r\n)
output:
D:\repos\TestWindbg\x64\Debug>TestWindbg.exe
DC288E0B39EA16B4E9455F82FF265A67:1213:TestDBG
áááááááááááááááá
I open exe in windbg and I saw while(token_string) is not NULL after first time. But is must?
WinDbg image : "https://i.ibb.co/60nHk5S/Untitled.png"
What is problem? Thanks for reading
Jeffrey Shao - MSFT :Thank you for reply but this is not solution(but I changed my code PBYTE TO PCHAR). The problem is that strtok_s is a string function for this reason you must add NULL byte after buff. Like HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(SIZE_T)FileSize + 1) #1 for NULL character . HeapAlloc alloc buff size:FileSize and +1 For Null...
Thanks for blabb and Daniel Sęk:
I just change some types of pData and token_string.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
BOOL TestMD5(CONST WCHAR* MD5_DATABASE_FILE)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD FileSize = 0;
DWORD dwReaded = 0;
char* pData = NULL;
BOOL bRead = FALSE;
char* token_string = NULL;
PCHAR context = NULL;
CONST PCHAR delimeter = "\r\n";
hFile = CreateFileW(
MD5_DATABASE_FILE,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (hFile == INVALID_HANDLE_VALUE)
{
wprintf(L"Can't open md5 database file: ");
return FALSE;
}
FileSize = GetFileSize(hFile, NULL);
if (FileSize == 0 || FileSize == INVALID_FILE_SIZE)
{
CloseHandle(hFile);
return FALSE;
}
pData = (char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(SIZE_T)FileSize + 1);
if (pData == NULL)
{
CloseHandle(hFile);
return FALSE;
}
bRead = ReadFile(hFile, pData, FileSize, &dwReaded, NULL);
if (bRead != TRUE || dwReaded != FileSize)
{
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return FALSE;
}
token_string = strtok_s(pData, delimeter, &context);
if (token_string == NULL)
{
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return FALSE;
}
do {
printf("%s\n", token_string);
} while (token_string = strtok_s(NULL, delimeter, &context));
HeapFree(GetProcessHeap(), 0, pData);
CloseHandle(hFile);
return TRUE;
}
int main(void)
{
WCHAR* MD5_DATABASE_FILE = L"c:\\md5.txt";
TestMD5(MD5_DATABASE_FILE);
}
Output:
DC288E0B39EA16B4E9455F82FF265A67:1213:TestDBG + (\r\n)

Cmd.exe output Unicode external commands

I am trying to get unicode output from running cmd.exe commands. I see the /U switch only works for builtin commands like dir and not others like ipconfig.
If I change the name of my computer to someone like Chinese/Russian/Japanese language, and run ipconfig /all, it will display it in the console just fine. But when I use CreateProcesssW() and redirect my output to a pipe, it doesn't give me unicode back even though it is displaying it properly on the console.
#include <Windows.h>
#include <stdio.h>
int main() {
HANDLE hPipeRead, hPipeWrite;
SECURITY_ATTRIBUTES saAttr = { sizeof(SECURITY_ATTRIBUTES) };
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&hPipeRead, &hPipeWrite, &saAttr, 0))
return 0;
STARTUPINFO si = { sizeof(STARTUPINFO) };
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdOutput = hPipeWrite;
si.hStdError = hPipeWrite;
si.wShowWindow = SW_HIDE;
PROCESS_INFORMATION pi = { 0 };
WCHAR works[] = L"C:\\windows\\system32\\cmd.exe /u /c dir C:\\test";
WCHAR dont[] = L"cmd.exe /u /c ipconfig";
BOOL fSuccess = CreateProcessW(NULL, works, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
if (!fSuccess) {
CloseHandle(hPipeWrite);
CloseHandle(hPipeRead);
return 0;
}
BOOL bProcessEnded = FALSE;
for (; !bProcessEnded;) {
bProcessEnded = WaitForSingleObject(pi.hProcess, 50) == WAIT_OBJECT_0;
while (TRUE) {
CHAR *buf = NULL;
DWORD dwRead = 0;
DWORD dwAvail = 0;
if (!PeekNamedPipe(hPipeRead, NULL, 0, NULL, &dwAvail, NULL))
break;
if (!dwAvail)
break;
buf = HeapAlloc(GetProcessHeap(), 0, dwAvail);
if (buf == NULL) {
return 0;
}
if (!ReadFile(hPipeRead, buf, dwAvail, &dwRead, NULL) || !dwRead)
break;
printf("%ls", buf);
}
}
CloseHandle(hPipeWrite);
CloseHandle(hPipeRead);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
Sleep(10000);
return 0;
}
I am trying to figure out how to get unicode back from everything ran in the cmd.exe.

Obtaining handle to key with NtCreateKey/NtOpenKey

PURPOSE
I'm trying to make a function which will create a given sub key in the HKCU registry hive, or open the sub key if it already exists, then return TRUE.
NOTES
Let RegSidPath represent a fully qualified HKCU registry path with an user SID appended to it such as \\Registry\\User\\S-1-5-20-xxxxxx-xxxxxx-xxxxxxxx-1050
Let KeyToCreate represent a specific registry path such as \\Software\\MyCompany\\MySoftware\\MySubKey
CODE
I have the following function:
BOOL CreateHKCUKey(PWCHAR RegSidPath, PWCHAR KeyToCreate) {
UNICODE_STRING uString;
RtlInitUnicodeString(&uString, RegSidPath);
OBJECT_ATTRIBUTES ObjAttributes;
InitializeObjectAttributes(&ObjAttributes, &uString, OBJ_CASE_INSENSITIVE, 0, 0);
HANDLE BaseKeyHandle = NULL;
NTSTATUS Status = NtOpenKey(&BaseKeyHandle, KEY_CREATE_SUB_KEY, &ObjAttributes);
if (NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_NOT_FOUND) {
UNICODE_STRING KeyString = { 0 };
do {
PWCHAR NextSubKey = StrStrW((KeyString.Length == 0 ? KeyToCreate : KeyString.Buffer) + 1, L"\\");
DWORD CurrentKeyLength = lstrlenW(KeyToCreate) - lstrlenW(NextSubKey);
PWCHAR CurrentSubKey = PWCHAR(GlobalAlloc(GPTR, CurrentKeyLength + sizeof(WCHAR)));
if (CurrentSubKey != ERROR) {
memcpy(CurrentSubKey, KeyToCreate, CurrentKeyLength * sizeof(WCHAR));
CurrentSubKey[CurrentKeyLength] = UNICODE_NULL;
RtlInitUnicodeString(&KeyString, CurrentSubKey);
OBJECT_ATTRIBUTES KeyAttributes;
InitializeObjectAttributes(&KeyAttributes, &KeyString, OBJ_CASE_INSENSITIVE, &BaseKeyHandle, 0);
HANDLE CurrentHiveEntry = NULL;
Status = NtOpenKey(&CurrentHiveEntry, KEY_CREATE_SUB_KEY, &KeyAttributes);
if (RtlNtStatusToDosError(Status) == ERROR_BAD_PATHNAME) {
InitializeObjectAttributes(&KeyAttributes, &KeyString, OBJ_CASE_INSENSITIVE, &CurrentHiveEntry, 0);
DWORD DefaultDisposition;
Status = NtCreateKey(&CurrentHiveEntry, KEY_CREATE_SUB_KEY, &KeyAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, &DefaultDisposition);
if (NT_SUCCESS(Status)) {
if (StrCmpNW(KeyString.Buffer + uString.Length, KeyString.Buffer, lstrlenW(KeyToCreate) == 0))
return TRUE;
else continue;
} else break;
} else break;
BaseKeyHandle = CurrentHiveEntry;
}
} while (TRUE);
}
NtClose(BaseKeyHandle);
return FALSE;
}
PROBLEM
Whenever the code gets to this part of the function
Status = NtOpenKey(&CurrentHiveEntry, KEY_CREATE_SUB_KEY, &KeyAttributes);
if (RtlNtStatusToDosError(Status) == ERROR_BAD_PATHNAME) {
The return value is always ERROR_BAD_PATHNAME (161) even if the current sub key already exists.
QUESTION
What is the reason, and what am I doing wrong? Is there anything that I've done which is not correct, and how can I fix it?
NTSTATUS CreateKey(PHANDLE KeyHandle, ACCESS_MASK DesiredAccess, PWCHAR RegSidPath, PWCHAR KeyToCreate, PULONG Disposition)
{
UNICODE_STRING ObjectName;
RtlInitUnicodeString(&ObjectName, RegSidPath);
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, &ObjectName ,OBJ_CASE_INSENSITIVE };
NTSTATUS status = ZwOpenKey(&oa.RootDirectory, KEY_CREATE_SUB_KEY, &oa);
if (0 <= status)
{
ObjectName.Buffer = KeyToCreate;
do
{
ACCESS_MASK Access;
if (KeyToCreate = wcschr(++ObjectName.Buffer, '\\'))
{
ObjectName.Length = (USHORT)RtlPointerToOffset(ObjectName.Buffer, KeyToCreate);
Access = KEY_CREATE_SUB_KEY;
}
else
{
ObjectName.Length = (USHORT)wcslen(ObjectName.Buffer) * sizeof(WCHAR);
Access = DesiredAccess;
}
ObjectName.MaximumLength = ObjectName.Length;
status = ZwCreateKey(KeyHandle, Access, &oa, 0, 0, 0, Disposition);
NtClose(oa.RootDirectory);
oa.RootDirectory = *KeyHandle;
} while (0 <= status && (ObjectName.Buffer = KeyToCreate));
}
return status;
}
and use as
HANDLE hKey;
NTSTATUS status = CreateKey(&hKey, KEY_ALL_ACCESS,
L"\\REGISTRY\\USER\\S-***",
L"\\Software\\MyCompany\\MySoftware\\MySubKey", 0);
Unless you are writing a driver, use RegCreateKeyEx() instead. It handles all the logic of creating intermediate keys for you if they don't already exist. 1 function call, no looping needed.
HKEY hKey;
DWORD dwDisposition;
LONG lRet = RegCreateKeyExW(HKEY_USERS, L"S-1-5-20-xxxxxx-xxxxxx-xxxxxxxx-1050\\Software\\MyCompany\\MySoftware\\MySubKey", 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hKey, &dwDisposition);
if (lRet == 0)
{
...
RegCloseKey(hKey);
}
However, to access the HKEY_CURRENT_USER hive of a specific user, the preferred solution is to use RegOpenCurrentUser() or LoadUserProfile() instead of accessing HKEY_USERS directly:
// impersonate the desired user first, then...
HKEY hRootKey;
LONG lRet = RegOpenCurrentUser(samDesired, &hRootKey);
if (lRet == 0)
{
HKEY hKey;
DWORD dwDisposition;
lRet = RegCreateKeyExW(hRootKey, L"Software\\MyCompany\\MySoftware\\MySubKey", 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hKey, &dwDisposition);
if (lRet == 0)
{
...
RegCloseKey(hKey);
}
RegCloseKey(hRootKey);
}
// stop impersonating...
// obtain token to desired user first, then...
PROFILEINFO profile = {0};
profile.dwSize = sizeof(profile);
profile.dwFlags = PI_NOUI;
if (LoadUserProfile(hToken, &profile))
{
HKEY hKey;
DWORD dwDisposition;
LONG lRet = RegCreateKeyExW((HKEY)profile.hProfile, L"Software\\MyCompany\\MySoftware\\MySubKey", 0, NULL, REG_OPTION_NON_VOLATILE, samDesired, NULL, &hKey, &dwDisposition);
if (lRet == 0)
{
...
RegCloseKey(hKey);
}
UnloadUserProfile(hToken, profile.hProfile);
}
// release token ...

How do I configure WinHTTP Tracing programmatically?

I have a C application (not C++ or C#) that tests connectivity to our API from a client's perspective using WinHTTP. Here's code that downloads a file.
DWORD Measure(FILE* fout, LPCTSTR lpszUrl) {
int i;
DWORD dwResult = 0;
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
DWORD dwRequestSize = 0;
LPSTR pszOutBuffer;
BOOL bResults = FALSE;
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET hRequest = NULL;
WINHTTP_STATUS_CALLBACK status = NULL;
if (0 == dwResult) {
hSession = WinHttpOpen(_T("Test/1.0"), WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession == NULL) {
dwResult = GetLastError();
}
}
if (0 == dwResult) {
status = WinHttpSetStatusCallback(hSession, (WINHTTP_STATUS_CALLBACK)HttpCallback, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, NULL);
if (WINHTTP_INVALID_STATUS_CALLBACK == status) {
dwResult = GetLastError();
}
}
if (0 == dwResult) {
hConnect = WinHttpConnect(hSession, lpszUrl, INTERNET_DEFAULT_HTTPS_PORT, 0);
if (hConnect == NULL) {
dwResult = GetLastError();
}
}
if (0 == dwResult) {
hRequest = WinHttpOpenRequest(hConnect, L"GET", NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE | WINHTTP_FLAG_REFRESH);
if (hRequest == NULL) {
dwResult = GetLastError();
}
}
if (0 == dwResult) {
bResults = WinHttpSendRequest(hRequest,WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
}
if (0 == dwResult) {
if(!QueryPerformanceCounter(&liDownloadStart)){
dwResult = GetLastError();
}
}
if (bResults) {
bResults = WinHttpReceiveResponse(hRequest, NULL);
if (!bResults) {
dwResult = GetLastError();
}
}
if (dwResult == 0 && bResults) {
do {
dwSize = 0;
if( !WinHttpQueryDataAvailable( hRequest, &dwSize ) ){
dwResult = GetLastError();
}
if (0 == dwResult) {
dwRequestSize += dwSize;
}
pszOutBuffer = (LPSTR)malloc(dwSize+1);
if (!pszOutBuffer) {
dwResult = ERROR_OUTOFMEMORY;
}
if (dwResult == 0) {
ZeroMemory(pszOutBuffer, dwSize + 1);
if( !WinHttpReadData( hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded ) ){
dwResult = GetLastError();
}
free(pszOutBuffer);
}
} while (dwSize > 0 && dwResult == 0);
}
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
return dwResult;
}
I can enable tracing using the following module:
BOOL enable = TRUE;
WinHttpSetOption(NULL, WINHTTP_OPTION_ENABLETRACING, &enable, sizeof(enable));
Following the instructions in the article Capturing WinHTTP Logs, I could ask the user to enable tracing, including the path where files should be stored.
netsh winhttp set tracing trace-file-prefix="C:\Temp\dpws" level=verbose format=ansi state=enabled max-trace-file-size=1073741824
However, most folks running my application are technically challenged. They may forget to disable it when they are done.
How do I programmatically enable WinHTTP tracing for my process?

Resources