I trying to write a very simple app to debug a Win32 64-bit app. My end goal is to get the TIB and PEB of the remote thread, but for some reason the way I did this on 32-bit app is not working for 64-bit ones (Aside from looking at Esp vs Rsp and checking SegFs vs SegGs). The code I'm trying to use is here:
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>
int main(int argc, char *argv[]){
LDT_ENTRY entry;
DWORD pid;
HANDLE hThread;
HANDLE hSnapshot;
CONTEXT context;
context.ContextFlags = CONTEXT_CONTROL;
if(argc < 2){
printf("Usage: %s PID\n", argv[0]);
exit(1);
}
pid = atoi(argv[1]);
THREADENTRY32 te32;
te32.dwSize = sizeof(te32);
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,0);
while(Thread32Next(hSnapshot, &te32)){
if(pid == te32.th32OwnerProcessID){
hThread = OpenThread(THREAD_ALL_ACCESS, 0, te32.th32ThreadID);
if(!hThread)
exit(1);
if(SuspendThread(hThread) == (DWORD) -1)
exit(1);
if(!GetThreadContext(hThread, &context))
exit(1);
printf("Rsp = 0x%x\n", context.Rsp);
if(!GetThreadSelectorEntry(hThread, context.SegGs, &entry)){
LPSTR buff = NULL;
FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buff, 0, NULL);
printf("Error: %s\n", buff); //ERROR_NOT_SUPPORTED 50 0x32 The request is not supported.
LocalFree(buff);
exit(1);
}
}
}
CloseHandle(hSnapshot);
return 0;
}
but it's always throwing an error at "GetThreadSelectorEntry". The error code that's thrown is ERROR_NOT_SUPPORTED: The request is not supported.
I am not able to understand why it's not supported. Does anyone know why?
[EDIT]
Okay GetThreadSelectorEntry is not available to x86_64 processes, does anyone know how I can get the TIB/PEB addresses of a remote process?
Related
how do you get a read-lock on Windows? like on Linux you'd do
#include <fcntl.h>
#include <sys/file.h>
int main(int argc, char **argv){
int h=open(argv[0],O_RDONLY);
flock(h,LOCK_SH);
flock(h,LOCK_UN);
close(h);
}
what's the Windows equivalent?
LockFileEx for basic locking. For a very soft lock there are also opportunistic locks.
expanding on #Anders's answer, the answer is LockFileEx, and the type of lock is decided by the dwFlags arguments,
linux=>windows
LOCK_SH => 0
LOCK_EX => LOCKFILE_EXCLUSIVE_LOCK
LOCK_NB => LOCKFILE_FAIL_IMMEDIATELY
the Windows API is quite a bit more complex (and powerful) than the Linux one, allowing you to lock "just parts" of the file, but you're free to effectively lock the whole file by just specifying that you want "the first 18446744073709551615 bytes locked" (meaning you want the first 18.45 exabytes of the file locked...), you're also able to "lock bytes that doesn't exist yet", hence a rough port of the code in the top post would be:
#include <cstdint>
#include <iostream>
#include <windows.h>
int main(int argc, char **argv){
HANDLE handle = CreateFileA(argv[0], GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle == INVALID_HANDLE_VALUE) {
throw std::runtime_error("CreateFile failed with error " + std::to_string(GetLastError()) + " for " + std::string(argv[0]));
}
const DWORD allBitsSet = ~DWORD(0);
DWORD flags = 0; // LOCK_SH = 0, LOCK_EX = LOCKFILE_EXCLUSIVE_LOCK, LOCK_NB = LOCKFILE_FAIL_IMMEDIATELY
_OVERLAPPED overlapped1 = {0};
_OVERLAPPED overlapped2 = {0};
if (!LockFileEx(handle, flags, 0, allBitsSet, allBitsSet, &overlapped1)) {
throw std::runtime_error("LockFileEx failed with error " + std::to_string(GetLastError()));
}
if(!UnlockFileEx(handle, 0, allBitsSet, allBitsSet, &overlapped2)) {
throw std::runtime_error("UnlockFileEx failed with error " + std::to_string(GetLastError()));
}
CloseHandle(handle);
}
I ran into some troubles when attempting a Detours hook on CreateFile in this small program:
#include <windows.h>
#include <iostream>
int main(HINSTANCE hinst, HINSTANCE hPrevInstance, LPSTR cmdLine, int showCmd)
{
HANDLE file;
DWORD bytesRead, bytesWritten, pos;
TCHAR msg[1000];
std::cout << "Start creating file \"SampleFile.txt\"" << std::endl;
file = CreateFile(L"C:\\TestHook\\SampleFile.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
std::cout << "\"SampleFile.txt\" added into C folder" << std::endl;
CloseHandle(file);
return 0;
}
There is a DLL applied:
#include<windows.h>
#include<windows.h>
#include "C:\Detours\Detours-4.0.1\include\detours.h"
static HANDLE(WINAPI* TrueCreateFile)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile) = CreateFileW;
__declspec(dllexport) HANDLE WINAPI MyCreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD
dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
HANDLE hookFile = CreateFile(L"C:\\TestHook\\hookYouGo.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
std::cout << "CreateFile() is hooked...Meet other file name than you want" << std::endl;
CloseHandle(hookFile);
return hookFile;
}
BOOL WINAPI DLLMain(HINSTANCE hinst, DWORD reason_for_call, LPVOID lpReserved)
{
std::cout << "test" << std::endl;
if (reason_for_call = DLL_PROCESS_ATTACH)
{
DetourRestoreAfterWith();
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)TrueCreateFile, MyCreateFile);
DetourTransactionCommit();
}
return TRUE;
}
Once executing in Visual Studio '19 (OS Windows 10), it adds a new file into the target folder, but another than I expect. Instead of hookYouGo.txt, SampleHook.txt appears there as if hook attachment failed. Looking into API monitor after process finish, I don't find any evidence that DLL was applied as orderly as well. In command line, it's just the same, since I launch withdll.exe that runs into outputs like statements on SampleFile, but DLL stuff seems beyond that process. Both withdll.exe and main func program and DLL are inside the same folder, sure.
You are doing it the wrong way, you must get the function address in order to hook it.
Like this:
static HANDLE(WINAPI* TrueCreateFile)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile);
TrueCreateFile HookCreateFile;
HookCreateFile = (TrueCreateFile)GetProcAddress(GetModuleHandle("Kernel32.dll"), "CreateFile");
Then do the actual hooking:
DetourAttach(&(PVOID&)HookCreateFile, MyCreateFile);
I have no idea why this pipe is invalid. everything seems fine to me. This is just a test, i don't write or read from it. Anyone can tell me what's wrong?
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#define BUFSIZE 4096
int main()
{
HANDLE hPipe;
LPTSTR Pipename = TEXT("\\\\.\\pipe\\mypipe");
printf("Start Server\n");
for(;;)
{
hPipe = CreateNamedPipe( Pipename,
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
BUFSIZE,
BUFSIZE,
NMPWAIT_USE_DEFAULT_WAIT,
NULL );
if ( hPipe == INVALID_HANDLE_VALUE )
{
printf("CreatePipe failed");
return 0;
}
CloseHandle(hPipe);
}
return 1;
}
Without more detail about the error it is difficult to help. However, as a general rule create the server using CreateNamedPipe then use ConnectNamedPipe.
On the client side you can now use CreateFile, which ConnectNamedPipe is waiting for on the server side.
I wrote a simple application on Qt4 that modifier network adapter parameters, for that I have a slot called setInterfaceParams, implemented as so:
DWORD WinNetInterface::setInterfaceParams(QString index, QString ip, QString netmask, QString gateway)
{
DWORD res = NULL;
HINSTANCE lib = (HINSTANCE) LoadLibrary((WCHAR *)"iphlpapi.dll");
_SetAdapterIpAddress SetAdapterIpAddress = (_SetAdapterIpAddress) GetProcAddress(lib, "SetAdapterIpAddress");
PWSTR pszGUID = NULL;
//char *szGUID = (char *)index.toStdString().c_str();
QByteArray a = index.toLocal8Bit();
char *szGUID = a.data();
WideCharToMultiByte(CP_ACP, 0, pszGUID, -1, szGUID, sizeof(szGUID), NULL, NULL);
// Method 01
res = SetAdapterIpAddress(szGUID,
0,
inet_addr(ip.toStdString().c_str()),
inet_addr(netmask.toStdString().c_str()),
inet_addr(gateway.toStdString().c_str()));
// End of method 01
// Method 02
/*res = SetAdapterIpAddress("{422C5689-A17B-402D-A6A2-22CE13E857B5}",
0,
inet_addr("192.168.1.10"),
inet_addr("255.255.255.0"),
inet_addr("192.168.1.1"));*/
// End of method 02
return res;
}
When I click on button that connected to slot setInterfaceParams, I get segmentation fault. If I comment method01, nothing happen, the some thing happen when I use method02.
I tried this function on a simple c++ application and it is work fine, test on Windows XP SP3.
#include <windows.h>
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <iostream>
typedef DWORD (WINAPI *_SetAdapterIpAddress )(char *szAdapterGUID,
DWORD dwDHCP,
DWORD dwIP,
DWORD dwMask,
DWORD dwGateway);
int main()
{
HINSTANCE lib = (HINSTANCE) LoadLibrary("iphlpapi.dll");
_SetAdapterIpAddress SetAdapterIpAddress = (_SetAdapterIpAddress) GetProcAddress(lib, "SetAdapterIpAddress");
PWSTR pszGUID = NULL;
char szGUID[] = "{422C5689-A17B-402D-A6A2-22CE13E857B5}";
DWORD dwSize = 0;
WideCharToMultiByte(CP_ACP, 0, pszGUID, -1, szGUID, sizeof(szGUID), NULL, NULL);
DWORD res = SetAdapterIpAddress(szGUID,
0,
inet_addr("192.168.1.10"),
inet_addr("255.255.255.0"),
inet_addr("192.168.1.1"));
std::cout << res;
return 0;
}
LoadLibrary((WCHAR *)"iphlpapi.dll");
That can't work, the literal string is in 8-bits, casting it without real conversion doesn't make it wide, so the dll loading probably failed.
You should use the TEXT or _T macro around most of the literal strings passed to WinAPI functions to make them regular or wide depending on the compilation options:
LoadLibrary(_T("iphlpapi.dll"));
which will translate to either LoadLibrary("iphlpapi.dll"); or LoadLibrary(L"iphlpapi.dll");.
Also you should always check the value returned by the LoadLibrary and GetProcAddress functions, which return NULL if the call is unsuccessful.
#include <windows.h>
#include <stdio.h>
#include <Userenv.h>
#include <Wtsapi32.h>
int main() {
DWORD err;
err=GetLastError();
printf( "err001:%d\n",err);
HANDLE hTokenThis = NULL;
HANDLE hTokenDup = NULL;
HANDLE hThisProcess = GetCurrentProcess();
OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
err=GetLastError();
printf( "err002:%d\n",err);
DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED,NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
err=GetLastError();
printf( "err003:%d\n",err);
DWORD dwSessionId = WTSGetActiveConsoleSessionId();
WTSQueryUserToken(dwSessionId, hTokenDup);
//DWORD dwSessionId = 1;
SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD));
err=GetLastError();
printf( "err004:%d\n",err);
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "WinSta0\\Default";
LPVOID pEnv = NULL;
DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE);
err=GetLastError();
printf( "err005:%d\n",err);
CreateProcessAsUser(
hTokenDup,
NULL,
(char *)"notepad",
NULL,
NULL,
FALSE,
dwCreationFlag,
pEnv,
NULL,
&si,
&pi);
printf("here we go\n");
err=GetLastError();
printf( "err006:%d\n",err);
return 0;
}
Compile:
gcc -o session.exe session.c c://Windows/System32/kernel32.dll c://Window
s/System32/wtsapi32.dll -lUserenv
Running Result:
session.exe
err001:126
err002:126
err003:126
err004:1314
err005:203
here we go
err006:87
gcc version 4.5.2 (GCC) from mingw.
btw, just ignore the error 126.
My question is :
Why got error 1314?
I want to start a program in the interactive desktop from service by using CreateProcessAsUser without knowing the logon user and password.
Error 1314 is "A required privilege is not held by the client".
From the WTSQueryUserToken() docs (http://msdn.microsoft.com/en-us/library/aa383840.aspx):
To call this function successfully, the calling application must be running within the context of the LocalSystem account and have the SE_TCB_NAME privilege
Also your call to WTSQueryUserToken() should look like:
WTSQueryUserToken(dwSessionId, &hTokenDup);
And you'll need appropriate privileges for SetTokenInformation() enabled as well.
Bottom line is that you're trying to do something that Windows reserves for highly privileged processes, so you'll need to make sure your process is configured to run appropriately (maybe as a service that talks to a regular non-privileged process for user interaction).