-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathDirtboxHacks.cpp
More file actions
187 lines (161 loc) · 5.92 KB
/
DirtboxHacks.cpp
File metadata and controls
187 lines (161 loc) · 5.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// Miscellaneous hacks
#include "DirtboxEmulator.h"
#include "Native.h"
#define OP_TWO_BYTE 0x0F
#define OP_IN 0xEC
#define OP_OUT 0xEE
#define OP2_WBINVD 0x09
namespace Dirtbox
{
typedef struct DUMMY_KERNEL
{
IMAGE_DOS_HEADER DosHeader;
DWORD Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_SECTION_HEADER SectionHeader;
} *PDUMMY_KERNEL;
HANDLE CurrentDirectory;
LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo);
}
// Exception handler that skips over privileged instructions
LONG WINAPI Dirtbox::ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo)
{
PEXCEPTION_RECORD Except = ExceptionInfo->ExceptionRecord;
PCONTEXT Context = ExceptionInfo->ContextRecord;
switch (Except->ExceptionCode)
{
case EXCEPTION_PRIV_INSTRUCTION:
{
// The only privileged instructions that we encounter here are
// in, out, and wbinvd.
BYTE Opcode = *(BYTE *)Context->Eip;
Context->Eip += 1;
switch (Opcode)
{
case OP_TWO_BYTE:
Opcode = *(BYTE *)Context->Eip;
Context->Eip += 1;
if (Opcode == OP2_WBINVD)
break;
else
return EXCEPTION_CONTINUE_SEARCH;
break;
case OP_IN:
Context->Eax &= 0xFFFFFF00;
break;
case OP_OUT:
break;
default:
return EXCEPTION_CONTINUE_SEARCH;
}
return EXCEPTION_CONTINUE_EXECUTION;
}
default:
return EXCEPTION_CONTINUE_SEARCH;
}
}
VOID Dirtbox::InitializeException()
{
if (AddVectoredExceptionHandler(1, &ExceptionHandler) == NULL)
FatalPrint("InitializeException: Could not add exception handler.");
DebugPrint("InitializeException: Exception handler added successfully.");
}
// this is needed to satisfy XapiRestrictCodeSelectorLimit in the runtime.
VOID Dirtbox::InitializeDummyKernel()
{
PDUMMY_KERNEL DummyKernel = (PDUMMY_KERNEL)VirtualAlloc(
(PVOID)DUMMY_KERNEL_ADDRESS, sizeof(DUMMY_KERNEL),
MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE
);
if (DummyKernel == NULL)
FatalPrint("InitializeDummyKernel: Could not turn allocate dummy kernel.");
memset(DummyKernel, 0, sizeof(DUMMY_KERNEL));
// XapiRestrictCodeSelectorLimit only checks these fields.
DummyKernel->DosHeader.e_lfanew = sizeof(IMAGE_DOS_HEADER); // RVA of NtHeaders
DummyKernel->FileHeader.SizeOfOptionalHeader = 0;
DummyKernel->FileHeader.NumberOfSections = 1;
// as long as this doesn't start with "INIT"
strncpy_s((PSTR)DummyKernel->SectionHeader.Name, 8, "DONGS", 8);
DebugPrint("InitializeDummyKernel: Dummy kernel initialized successfully.");
}
VOID Dirtbox::InitializeDrives()
{
CHAR CurrentPath[MAX_PATH];
GetCurrentDirectoryA(MAX_PATH, CurrentPath);
CurrentDirectory = CreateFileA(
CurrentPath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL
);
if (CurrentDirectory == INVALID_HANDLE_VALUE)
FatalPrint("InitializeDrives: Could not open current directory.");
// Xbox partitions
CreateDirectoryA("C_", NULL);
CreateDirectoryA("D_", NULL);
CreateDirectoryA("T_", NULL);
CreateDirectoryA("U_", NULL);
CreateDirectoryA("Z_", NULL);
// Dummy folder for volume openings.
CreateDirectoryA("Dummy", NULL);
DebugPrint("InitializeDrives: Virtual drives initialized successfully.");
}
BOOLEAN Dirtbox::IsValidDosPath(PANSI_STRING String)
{
return String->Length >= 3 &&
strpbrk(String->Buffer, "CDTUZcdtuz") == String->Buffer &&
strncmp(String->Buffer + 1, ":\\", 2) == 0;
}
NTSTATUS Dirtbox::ConvertObjectAttributes(
POBJECT_ATTRIBUTES Destination, PUNICODE_STRING ObjectName, PWSTR Buffer,
PXBOX_OBJECT_ATTRIBUTES Source
)
{
if (Source->RootDirectory == OB_DOS_DEVICES)
{
// validate correctness of path
if (!IsValidDosPath(Source->ObjectName))
{
DebugPrint("ConvertObjectAttributes: Invalid path name.");
return STATUS_OBJECT_NAME_INVALID;
}
// build the new path
RtlInitEmptyUnicodeString(ObjectName, Buffer, MAX_PATH);
RtlAnsiStringToUnicodeString(ObjectName, Source->ObjectName, FALSE);
// ':' is not an allowed char in names, so replace it with _
ObjectName->Buffer[1] = L'_';
/*
// D:\ refers to current directory
if (ObjectName->Buffer[0] == L'D' || ObjectName->Buffer[0] == L'd')
{
// remove D:\ in the beginning of string
ObjectName->Length -= 3;
for (SHORT i = 0; i < ObjectName->Length; i++)
ObjectName->Buffer[i] = ObjectName->Buffer[i + 3];
ObjectName->Buffer[ObjectName->Length + 1] = L'\0';
}
else
{
// ':' is not an allowed char in names, so replace it with _
ObjectName->Buffer[1] = L'_';
}
*/
}
else if (Source->RootDirectory == NULL)
{
// build the new path
RtlInitEmptyUnicodeString(ObjectName, Buffer, MAX_PATH);
RtlAppendUnicodeToString(ObjectName, L"Dummy");
}
else
{
DebugPrint("ConvertObjectAttributes: Invalid root directory.");
return STATUS_UNSUCCESSFUL;
}
// Convert XBOX_OBJECT_ATTRIBUTES to Windows NT OBJECT_ATTRIBUTES
Destination->Length = sizeof(OBJECT_ATTRIBUTES);
Destination->ObjectName = ObjectName;
Destination->Attributes = Source->Attributes;
Destination->RootDirectory = CurrentDirectory;
Destination->SecurityDescriptor = NULL;
Destination->SecurityQualityOfService = NULL;
return STATUS_SUCCESS;
}