Showing posts with label OS hacks. Show all posts
Showing posts with label OS hacks. Show all posts

A simple note on port access under windows NT

I intend to write a short on port access under windows now.

1. Using Microsoft VB, you can not do port access stuff, whatever, NO. If you really need, use c/c++ to write the function, and port to dll, call it from your vb project.

2. under DOS, win98, winMe, port is open accessible; however, for NT kernel system, like winNT, win2000, winXP, direct port access is blocked; to access the port, there are two methods commonly adopted:

a) get/write a driver, like giveio.sys, and load it to grant access inside your project, prior to any port accessing;

b) if you code is already there, or you only have the executable, use portTalk/allowIo to invoke your application and grant access to some port by command line arguments;

------------------------------------------------------------------------------------------
how is the blocking mechanism under NT kernel system working?

basically, under NT kernel, programs run in two mode, user mode and kernel mode. User mode are considered unstable, and thus restricted by OS. it works in this way:
a> user mode program runs in privilege level ring 3, and kernel mode program runs in privilege leve ring 0.
b> if a program request to access a port, the OS checks for two things:
1) if the program runs in ring 0, ok, go; otherwise
2) check the IOPM mapping in TSS, if the corresponding bit for the port is cleared, ok, go, otherwise
3) blocked!!!

--------------------------------------------------------------------------------------------
how does driver like giveio.sys or port talk walk around the limitation?

it changes the IOPM to grant access for certain process; how? the answer is , there is some un-documented api under windows to manipulate the bit in IOPM.

------------------------------------------------------------------------------------
what is IOPM?

forget about the details if you are not interested. it is some system managed memory, each bit inside represents the access right for one port. Bit 1(default value) means blocking, and bit 0 means green light.

How is the details? how does it really really works?

do not ask; u need something like SoftICE or winDBG to dig into TSS to see it yourself. did i? NOT yet. It is not straight forward to me.

anything wrong or inaccurate above, leave a comment. thanks

From "Undocumented Windows 2000 Secrets" (1)

The first obstacle is that debugging usually involves two separate machines connected by a cable—one running the debugger, the other one hosting the debuggee.

However, there is a much easier way, eliminating the necessity of a second machine, if live debugging is not a requirement. For example, if a buggy application throws an unhandled exception causing the infamous NT “Blue Screen Of Death” (BSOD) to pop up, you can choose to save the memory image that was in effect right before the crash to a file and examine this crash dump after rebooting. This technique is usually called post mortem debugging (post mortem
is Latin and means “after death”).

A really really nice page!

hi, all, here, look here:
http://www.rawol.com/?topic=77

a free download of Undocumented Windows 2000 Secrets in nice pdf format for download or online browse!!!

Let's start from how to access ports under Windows NT

From KMD:

Most strange thing here is that we have accessed the SMOS memory without the system stops us. As I have already mentioned above, the access to I/O ports is protected under Windows NT. Executing IN or OUT instruction in user-mode will cause process termination. But we have touched them. How it can be? Well, it becomes possible due to the giveio driver.

The driver's code is based on well-known example (giveio) by Dale Roberts. I have decided it will be appropriate to mention here.

Our driver changes the I/O permission bit map (IOPM) that allows the process free access to the I/O ports. Each process has its own I/O permission bit map, thus access to the individual I/O ports can be granted to the individual process. Each bit in the I/O permission bit map corresponds to the byte I/O port. If this bit is set, the access to the corresponding port is forbidden, if it is clear the process may access this I/O port. Since the I/O address space consists of 64K individually addressable 8-bit I/O ports, the maximum IOPM size is 2000h bytes.

The purpose of the TSS is to save the state of the processor during task or context switches. For performance reasons, Windows NT does not use this architectural feature and maintains one base TSS that all processes share. This means that IOPM is also shared. So any changes to it are not private for particular process but are system-wide.

There are some undocumented functions in the ntoskrnl.exe to manipulate with the IOPM:
Ke386QueryIoAccessMap and Ke386SetIoAccessMap.
Ke386QueryIoAccessMap proto stdcall dwFlag:DWORD, pIopm:PVOID

Ke386QueryIoAccessMap copies current IOPM by the size of 2000h bytes from TSS to the memory buffer pointed to by pIopm parameter.

Ke386SetIoAccessMap copies specified IOPM by the size of 2000h from the memory buffer pointed to by pIopm parameter to TSS.

[some comment from http://www.nsfocus.net/index.php?act=magazine&do=view&mid=2205]

I think these comments are extremely necessary, so I decided to concatenate them here.

通过前面对 NT 系统中 KTSS 结构和实际内存的分析,我们可以了解:NT 环境下,每个进程单独维护了一个 TSS 内存区域,其中由 TSS 内部维护了一个全部标志位置 1 的 IOPM 表,在 TSS 末尾还维护了另外一个实际中承担端口管理工作的 IOPM 表。Ke386SetIoAccessMap 函数(ntos\ke\i386\iopm.c:80)和 Ke386QueryIoAccessMap 函数(ntos\ke\i386\iopm.c:235)就是系统提供用来读写这两个 IOPM 表的函数。而 Ke386IoSetAccessProcess 函数(ntos\ke\i386\iopm.c:318)则指定进程到底使用哪个 IOPM 表。

对前两个函数来说,MapNumber指定要对哪个表进行操作。系统定义了一个 IO_ACCESS_MAP_NONE = 0 常量表示在 TSS 后面那个真实 IOPM 表,而其他的索引对应于 KTSS.IoMaps[] 数组。此数组大多数情况下只有一个表项,也就是说 MapNumber 为 0 时表示 TSS 后面那个 IOPM;为 1 时表示 TSS 内部的 KTSS.IoMaps[0]。 Ke386QueryIoAccessMap 函数只是简单的根据 MapNumber 判断是将 IoAccessMap 内容全部置位(MapNumber = 0)、还是从 TSS 中复制对应的表 (0 < iopm_count =" 1)。伪代码如下:

#define IOPM_COUNT 1
#define IOPM_SIZE 8192 // Size of map callers can set.

BOOLEAN Ke386QueryIoAccessMap(ULONG MapNumber, PKIO_ACCESS_MAP IoAccessMap)
{
if(MapNumber > IOPM_COUNT) return FALSE;

if(MapNumber == IO_ACCESS_MAP_NONE)
{
memset(IoAccessMap, -1, IOPM_SIZE);
}
else
{
void *pIOPM = &(KiPcr()->TSS->IoMaps[MapNumber-1].IoMap);

memcpy(IoAccessMap, pIOPM, IOPM_SIZE);
}
return TRUE;
}

而 Ke386SetIoAccessMap 在 MapNumber 为 0 时直接返回 FALSE,因为 TSS 后的那个表是不允许修改的;对其他情况,函数将 IoAccessMap 中的内容复制回 TSS 的 IOPM 表中,并在多处理器情况下通知其他处理器重新载入 IOPM 表。伪代码如下:

BOOLEAN Ke386SetIoAccessMap(ULONG MapNumber, PKIO_ACCESS_MAP IoAccessMap)
{
if((MapNumber > IOPM_COUNT) (MapNumber == IO_ACCESS_MAP_NONE)) return FALSE;

void *pIOPM = &(KiPcr()->TSS->IoMaps[MapNumber-1].IoMap);

memcpy(pIOPM, IoAccessMap, IOPM_SIZE);

KiPcr()->TSS->IoMapBase = GetCurrentProcess()->IopmOffset;

// 通知其他处理器重设 IOPM

return TRUE;
}

Ke386IoSetAccessProcess 函数则简单地修改当前 TSS 的 IOPM 偏移为 MapNumber 指定的 IOPM 表偏移,并在多 CPU 情况下通知其他 CPU 重新载入 IOPM 偏移。计算偏移算法如下:

#define KiComputeIopmOffset(MapNumber) \
(MapNumber == IO_ACCESS_MAP_NONE) ? \
(USHORT)(sizeof(KTSS)) : \
(USHORT)(FIELD_OFFSET(KTSS, IoMaps[MapNumber-1].IoMap))
USHORT MapOffset = KiComputeIopmOffset(MapNumber);

完整的使用流程代码如下:

#define IOPM_SIZE 8192 // Size of map callers can set.

typedef UCHAR KIO_ACCESS_MAP[IOPM_SIZE];
typedef KIO_ACCESS_MAP *PKIO_ACCESS_MAP;

PKIO_ACCESS_MAP IOPM_local = MmAllocateNonCachedMemory(sizeof(IOPM));
if(IOPM_local == 0)
return STATUS_INSUFFICIENT_RESOURCES;

Ke386QueryIoAccessMap(1, IOPM_local);

// 修改 IOPM_Local 内容打开需要使用的端口
Ke386SetIoAccessMap(1, IOPM_local);
Ke386IoSetAccessProcess(PsGetCurrentProcess(), 1);

I will make the English translation later.

from KMD tutorial

Windows NT internals are divided by two distinct part concerning both address space and code permissions and responsibilities.
Address space sharing is amazingly simple. Whole four gigabytes of memory available in 32-bit architecture divided by two equal parts (4GT RAM Tuning and Physical Address Extension omitted as an exotic case). The address space for a user-mode processes is mapped into the lower 2GB of linear memory at addresses 00000000 - 7FFFFFFFh. The upper 2GB of linear memory address range 80000000h - 0FFFFFFFFh maps system components such as device drivers, system memory pools, system data structures etc. Sharing permissions and responsibilities is slightly complicated.

The architecture of the Intel x86 processor defines four privilege levels (known as rings). Windows uses privilege level 0 (or ring 0) for kernel-mode and privilege level 3 (or ring 3) for user-mode. The reason Windows uses only two levels is that some of the hardware architectures that were supported in the past (such as Compaq Alpha and Silicon Graphics MIPS) implemented only two privilege levels.

Properly speaking the user-mode applications are completely separated from the operating system. It's good for the integrity of the operating system but it could be a headache for some kind of utility application such as debugging tools. Fortunately, unrestricted access provided by the kernel-mode drivers could be used to perform practically impossible tasks on behalf of user-mode applications. So, if you plan to access internal operating system functions or data structures that are not accessible in user-mode, the only way is to load a kernel-mode driver into the system address space. It's rather simple, yet reliable and completely supported by the operating system itself.

What is Delay loading DLL?

This is a popular terms cited under windows programming. What is really a delayed loading of DLL? You can get a rought idea from the following article from codeproject.com

http://www.codeproject.com/dll/Delay_Loading_Dll.asp

Normally, if you executable reference a API function in another DLL, windows loader will attempt to load the DLL into memory, and report error if the DLL is missing or out of date. If your application has a lot of DLL dependancy, then the loading process will be long, even if you just made one API call to each DLL.

Delay Loading of DLL simply means the DLL is not loaded until a call to the API inside has been made. By adding a few linker directive in the exe, the windows loader will be able to do so.

Disadvantage: if the underlying dll is missing, it will only be discovered when the call the API in dll has been made, and your program maybe terminated abruptly at run time. SO a Structure Exception Handler (SEH) is suggested.

What is MBR, and How it works?

the following information is based on my understanding of the following webpage, please read the original site for detailed explanation.
http://mirror.href.com/thestarman/asm/mbr/Win2kmbr.htm

MBR is the first sector in the first cylinder, first head of the current Master hard drive active partition. It is a 512 bytes (one sector) long paragraph of data and code.

* what is inside the MBR? -- under windows, you can use any binary reader to open c:\windows\system32\dmadmin.exe, and the MBR code itself is found between offsets 34E28h through 35027h. It contains some machine code, some error message, some OS related remarks and last but not least, the partition table.

* how it is invoked? -- I am not very sure about my answer, but I do provide short answer here. remember the DOS interrupt int 13? Yes, int 13 is used in BIOS to load this particular sector into memory location 0000:7c00. The processor will execute the code from 0000:7c00, and somewhere at 0000:7c1B, the code will try to copy the rest of the sector (about 485 bytes long) to another memory location.

[why make another copy? because this copy in memory will be overwritten by boot sector of the active partition later. the remaining code has to find itself a new home. :) ]

The website listed above provide some code comment to the disassembled MBR machine code. nice work!

How does IBM compatible PC boot up?

precaution: do not take my statement word by word, this is just very very rough and inaccurate guide on this topic.

--- it all starts with a cold reset.

--- the processor will try to look for a BIOS rom at a pre-defined sytem IO address (F000:FFF0)

--- if the ROM is found and it is valid, processor will try to execute the BIOS code in the rom, and doing all hardware validation and initialization stuff (so called Power On Self Check, or POST)

[ after the memory controller is initialized successfully, part of the ROM code and data will be copied (or you call shadowed) to the DRAM, and execution continues from there.]

--- when all this done, and a default or user preferred fix storage is detected (e.g. a hdd)

--- processor will look into the first sector of the hdd partition (so called Master boot record, or MBR)

[MBR is a 512 bytes long area in hdd, and it contains the disk partition, vendor info, and something related to 2nd stage boot loader, while the MBR is considered the 1st stage boot loader]

--- MBR machine code may boot directly to OS or it may pass control to 2nd stage boot loader (normally, it refers to famous names: LILO, GRUB or window NTLDR)

[these 2nd stage boot loader normally have some user interaction shell, and allows user to boot from one of several installed OSes]

windows exe file format, etc

some un-organized notes...

Early versions of Microsoft windows OS are DOS-based, from windows 3.0 to Windows Me, the GUI are just graphical shells of the underlying DOS system. However, the DOS basis is discarded when Microsoft moved on to Windows NT and its late variations (so called windows 2000 and windows xp).

For a executionable file to be excuted by the operating system, some common consensus over fie format has to be agreed. How does it tell the OS to find libraries, etc. This leads to the area of windows exe file format. In the current prevailing windows platform, PE (portable executable) format is assumed. Portable executable basically targets at portability over all all 32 bit Microsoft OSes. PE is developed based on the old COFF (common object file format) format on Unix.