如何在64位Windows上准确修改本地描述符表?
其目的是通过如何在64位Windows上准确修改本地描述符表?,windows,x86-64,16-bit,mmu,Windows,X86 64,16 Bit,Mmu,其目的是通过modify_ldt()系统调用为16位寻址启用16位段,就像在64位Linux内核上一样 我无法找到Cygwin是否提供了一个包装器,我几乎不知道它是关于NtSetLdtEntries之类的东西: typedef struct { ULONG Start; ULONG Length; LDT_ENTRY LdtEntries[1]; } PROCESS_LDT_INFORMATION, *PPROCESS_LDT_INFORMATION; 请注意,这与vm
modify_ldt()
系统调用为16位寻址启用16位段,就像在64位Linux内核上一样
我无法找到Cygwin是否提供了一个包装器,我几乎不知道它是关于NtSetLdtEntries
之类的东西:
typedef struct
{
ULONG Start;
ULONG Length;
LDT_ENTRY LdtEntries[1];
} PROCESS_LDT_INFORMATION, *PPROCESS_LDT_INFORMATION;
请注意,这与vm86模式无关(这是Microsoft在32位系统上使用的不同方法)。如上所述,这种方式在Linux上用于以保护模式运行16位代码,而无需任何仿真。有关更多信息,请参阅
当然,如果默认情况下不支持,则可以修改系统文件。在基于x86的windos上(在xp和win 8.1 x86上测试),可以在LDT表中设置几个描述符并使用它。这可以通过NtSetInformationProcess
和ProcessLdtInformation
(未记录)来完成,或者,如果我们只需要设置1或2个选择器-更易于使用的未记录api:
EXTERN_C
__declspec(dllimport)
NTSTATUS
NTAPI
NtSetLdtEntries
(
__in_opt ULONG Selector1,
__in SEGMENT_ENTRY LdtEntry1,
__in_opt ULONG Selector2,
__in SEGMENT_ENTRY LdtEntry2
);
因此,我们需要分配1个或多个段\ u条目(或在winnt.h中声明),为段分配内存,并调用api。我没有太注意16位代码和填充实际描述符,只通过LDT选择器(分配给ES)检查内存填充,然后通过“普通”选择器读取
typedef struct SEGMENT_ENTRY
{
ULONG LimitLow : 16;
ULONG BaseLow : 16;
ULONG BaseMid : 8;
ULONG Type : 4;
ULONG IsGegment : 1;// = 1
ULONG DPL : 2;
ULONG P : 1;// Present
ULONG LimitHi : 4;
ULONG AVL : 1;// Available For software use
ULONG L : 1;// Long-mode segment
ULONG D : 1;// Default operand size
ULONG G : 1;// Granularity
ULONG BaseHi : 8;
}*PSEGMENT_ENTRY;
typedef struct PROCESS_LDT_INFORMATION
{
ULONG StartSelector;
ULONG Length;
SEGMENT_ENTRY LdtEntries[];
} *PPROCESS_LDT_INFORMATION;
EXTERN_C
__declspec(dllimport)
NTSTATUS
NTAPI
NtSetLdtEntries
(
__in_opt ULONG Selector1,
IN SEGMENT_ENTRY LdtEntry1,
__in_opt ULONG Selector2,
IN SEGMENT_ENTRY LdtEntry2
);
NTSTATUS TestLdt()
{
PVOID BaseAddress = 0;
SIZE_T RegionSize = 0x100000;//1mb
NTSTATUS status = NtAllocateVirtualMemory(NtCurrentProcess(), &BaseAddress, 0, &RegionSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (0 <= status)
{
#if 1
SEGMENT_ENTRY LdtEntry = {};
LdtEntry.LimitLow = 0xffff;
LdtEntry.BaseLow = ((ULONG_PTR)BaseAddress) & 0xFFFF;
LdtEntry.BaseMid = ((ULONG_PTR)BaseAddress >> 16) & 0xff;
LdtEntry.BaseHi = ((ULONG_PTR)BaseAddress >> 24) & 0xff;
LdtEntry.P = 1;
LdtEntry.DPL = 3;
LdtEntry.IsGegment = 1;
LdtEntry.Type = 2;//ldt
status = NtSetLdtEntries(8, LdtEntry, 0, LdtEntry);
#else
const ULONG cb = sizeof(PROCESS_LDT_INFORMATION) + 1 * sizeof(LDT_ENTRY);
PPROCESS_LDT_INFORMATION LdtInfo = (PPROCESS_LDT_INFORMATION)alloca(cb);
LdtInfo->Length = 1 * sizeof(LDT_ENTRY);
LdtInfo->StartSelector = 8;
SEGMENT_ENTRY* LdtEntry = LdtInfo->LdtEntries;
LdtEntry->LimitLow = 0xffff;
LdtEntry->BaseLow = ((ULONG_PTR)BaseAddress) & 0xFFFF;
LdtEntry->BaseMid = ((ULONG_PTR)BaseAddress >> 16) & 0xff;
LdtEntry->BaseHi = ((ULONG_PTR)BaseAddress >> 24) & 0xff;
LdtEntry->L = 0;
LdtEntry->D = 0;
LdtEntry->G = 0;
LdtEntry->AVL = 0;
LdtEntry->P = 1;
LdtEntry->DPL = 3;
LdtEntry->IsGegment = 1;
LdtEntry->Type = 2;//ldt
status = NtSetInformationProcess(NtCurrentProcess(), ProcessLdtInformation, LdtInfo, cb);
#endif
if (0 <= status)
{
DbgPrint("%s\n", BaseAddress); // print empty string
#ifdef _X86_
__asm {
push edi
mov ax,0xf
mov dx,es
mov es,ax
mov ecx,32
mov al,0x33
xor edi,edi
rep stosb
mov es,dx
pop edi
}
#endif
DbgPrint("%s\n", BaseAddress);// print 33333333...
}
NtFreeVirtualMemory(NtCurrentProcess(), &BaseAddress, &RegionSize, MEM_RELEASE);
}
return status;
}
typedef结构段\u条目
{
乌龙有限公司:16家;;
乌龙-巴塞洛:16;
乌龙巴塞米德:8;
乌龙型4例;
ULONG IsGegment:1;//=1
乌龙DPL:2;
ULONG P:1;//当前
乌龙利米提:4;
ULONG AVL:1;//可供软件使用
ULONG L:1;//长模式段
ULONG D:1;//默认操作数大小
ULONG G:1;//粒度
乌龙巴塞:8;
}*分段录入;
类型定义结构进程\u LDT\u信息
{
乌隆星选仪;
乌龙长度;
段/分录第十项[];
}*程序及资料;
外部
__declspec(德林波特)
NTSTATUS
恩塔皮
NtSetLdtEntries
(
__在_optulong选择器1中,
在段_条目LdtEntry1中,
__在_optulong选择器2中,
在段_条目LdtEntry2中
);
NTSTATUS TestLdt()
{
PVOID基址=0;
大小\u T区域大小=0x100000;//1mb
NTSTATUS status=NtAllocateVirtualMemory(NtCurrentProcess(),&BaseAddress,0,&RegionSize,MEM\u COMMIT,PAGE\u EXECUTE\u READWRITE);
如果(0>16)&0xff;
LdtEntry.BaseHi=((ULONG_PTR)BaseAddress>>24)和0xff;
Ldentry.P=1;
LdtEntry.DPL=3;
LdtEntry.IsGegment=1;
LdtEntry.Type=2;//ldt
状态=ntsetldtentry(8,LdtEntry,0,LdtEntry);
#否则
const ULONG cb=sizeof(过程LDT信息)+1*sizeof(LDT条目);
p进程\u LDT\u信息LdtInfo=(进程\u LDT\u信息)alloca(cb);
LdtInfo->Length=1*sizeof(LDT\u条目);
LdtInfo->StartSelector=8;
分段输入*LdtEntry=LdtInfo->LdtEntry;
LdtEntry->LimitLow=0xffff;
LdtEntry->BaseLow=((ULONG_PTR)BaseAddress)&0xFFFF;
LdtEntry->BaseMid=((ULONG_PTR)BaseAddress>>16)和0xff;
LdtEntry->BaseHi=((ULONG_PTR)BaseAddress>>24)和0xff;
Ldentry->L=0;
LdtEntry->D=0;
LdtEntry->G=0;
LdtEntry->AVL=0;
LdtEntry->P=1;
LdtEntry->DPL=3;
LdtEntry->IsGegment=1;
LdtEntry->Type=2;//ldt
状态=NtSetInformationProcess(NtCurrentProcess(),ProcessLdtInformation,LdtInfo,cb);
#恩迪夫
如果(0@RbMm)为什么 ? 请注意,我不是说Vm86。目标是16位寻址而不是实模式。我描述的方式适用于Linux64位。@RbMm Longmode仍然使用CS确定代码段,使用新的L位在32位和64位子模式之间切换,并且仍然可以使用Sz位.t启用很少使用的16位模式任何windows x64都不支持这一点。在xp上的x86上-这正是可以实现的,是后者-不检查。64位xp-不存在。存在64位win 2003:)再看看-@RbMm:Harold是对的,这在CPU级别上是绝对可能的。长模式内核可以运行16位用户空间。它不是vm86,它就像32位兼容模式(在64位内核下),但默认操作数大小和地址大小为16位。就像32位内核下的16位代码描述符一样。这不是实模式,因此只能通过使用段选择器索引到LDT/GDT来设置段基。但是,是的,我非常确定它们可以是非零的,就像在compat模式下一样。@RbMm:是的,我知道你已经说过x64 Windows doesn不支持这样做。我想你或其他未来的读者可能有兴趣知道x86-64可以做什么,而Windows可以做什么。哦,我只是读了更多的评论,我看到OP还没有理解这一点。对不起,我不是想堆积和添加那些声称这应该是可能的评论,因为硬件可以做到。显然是的您还需要操作系统的支持,这样才能安全地进行操作ᴍᴍᴜ 不是Windows。所以它是受支持的。可能不受支持的是从userland修改它。@user2284570,不是这是x64 Windows不支持的,无论是从用户模式还是内核模式。在GDT中开始时必须是LDT的选择器,但在这里没有这样的选择器,并且您不能修改GDT本身。它需要由内核代码设置。支持相同的设置就像ᴘᴀᴇ 32位:包括驱动程序在内的第三方代码无法访问它。@user2284570-同样,这是cpu支持的,但没有api(从用户或内核模式)在windows中执行此操作。如果您自己尝试执行此操作,将与op系统冲突。因此,不会发生任何事件或系统崩溃。例如,cpu也支持关闭分页。但您不能在windows中执行此操作windows@user2284570-但问题是关于windows,而不是reactOS。您不能在x64 windos中执行此操作,不是因为这不是