Search This Blog
Tuesday, July 12, 2011
Windows Startup Routine
1. POST (Power On Self Test)
2. BIOS loads MBR into memory
3. MBR reads the first sector from the bootable partition and the code in the first sector loads the Bootmgr into memory
4. Bootmgr loads the boot loader, Winload.exe (Ntldr in the past)
Winload.exe
- loads the appropriate kernel and HAL images (Ntoskrnl.exe and Hal.dll)
- reads registry to determine boot device drivers and loads them.
- calls KiSystemStartup in Ntoskrnl.exe
Ntokrnl.exe
- phase 0
prepares data structures for services to run in phase 1
calls the object manager, security reference monitor, process
manager, user-mode debugging framework, and the Plug and Play manager initialization
- phase 1
calls more initializations i.e. power manager, memory manager
I/O manager initialization
- creates I/O manager object types i.e. device, driver
- perform boot-start drivers initialization and system-start device drivers are loaded and initialized
- the Session manager(Smss) process is started. Smss is responsible for creating user-mode environment that provides the visible interface to Windows
Smss
- start the Windows subsystem
- start Csrss which is Client Server Runtime Process
- CSRSS: user-mode portion of the Win32 subsystem; Win32.sys is the kernel-mode portion.
- launches Windows Initialization Process (Wininit) and start the interactive logon manager process (Winlogon)
Wininit
- performs startup steps such as creating the initial window station and desktop objects
- creates SCM which initializes auto-start services and drivers
Once Winlogon validates the logon, Winlogon sets up the user environment and starts the shell(explorer)
That's it for now and hopefully, in the future I will try to add some diagram to describe what I wrote in the above.
Sunday, July 3, 2011
global/static variables - where are they?
int g_init_var1 = 3;
int g_init_var2 = 0;
int g_un_var;
int testfunc(int num)
{
int auto_var;
static int static_var_1 = 0;
static int static_var_2;
if (num == 1)
static_var_2 = num;
return 0;
}
int main(int argc, char *argv[])
{
int num;
scanf("%d", &num);
testfunc(num);
return 0;
}I just declared two global variables and two static variables and after that I compiled the code with /FA option to produce assembly code. PUBLIC _g_init_var1
PUBLIC _g_init_var2
_DATA SEGMENT
COMM _g_un_var:DWORD
_DATA ENDS
_BSS SEGMENT
_g_init_var2 DD 01H DUP (?)
?static_var_1@?1??testfunc@@9@9 DD 01H DUP (?) ; `testfunc'::`2'::static_var_1
_BSS ENDS
_DATA SEGMENT
_g_init_var1 DD 03H
$SG2474 DB '%d', 00H
ORG $+1
$SG2475 DB '%d', 0aH, 00H
_DATA ENDS
_BSS SEGMENT
?static_var_2@?1??testfunc@@9@9 DD 01H DUP (?) ; `testfunc'::`2'::static_var_2
; Function compile flags: /Odtp
_BSS ENDSAs expected cl put g_un_var into 'data' segment because it is not defined. But I found it interesting to see what happens to the global variables that are defined. The global variables that are defined to be zero are actually located in 'bss' segment while the global variables that are defined to be non-zero are located in 'data' segment.For static variables, we see the same pattern. The only thing I would comment is that g_init_var1/g_init_var2 is the type of PUBLIC but g_un_var is the type of COMM. Linker will concatenate all PUBLIC segments having the same name to form a single, contiguous segment. But with COMM, it creates a communal variable which behaves like external variables and communal variables are allocated by the linker. In a nutshell, they are just like global variables but we cannot assign them initial values and the only drawback of using communal variable is that they may not appear in consecutive memory locations.
Disassembly of section .data:
00000000006008b8 <__data_start>:
6008b8: 00 00 add %al,(%rax)
...
00000000006008bc <g_init_var1>:
6008bc: 03 00 add (%rax),%eax
...
00000000006008c0 <static_var_1.2130>:
6008c0: 01 00 add %eax,(%rax)
...
Disassembly of section .bss:
00000000006008c8 <dtor_idx.6147>:
...
00000000006008d0 <completed.6145>:
6008d0: 00 00 add %al,(%rax
...
00000000006008d4 <g_init_var2>:
6008d4: 00 00 add %al,(%rax)
...
00000000006008d8 <static_var_2.2131>:
6008d8: 00 00 add %al,(%rax)
...
00000000006008dc <g_un_var>:
6008dc: 00 00 add %al,(%rax)
...
Friday, July 1, 2011
Useful links for Windows kernel development
- Windows Driver Kit Documentation
- Driver Development Intro
- DDKWizard Homepage - for VS integration
- Sources FILE - MSDN
- Getting started with the Windows Driver Development Environment
- Kernel-mode code signing walkthrough
- From Sample Code to Production Driver: What to change in the sample - MSDN
- ALE Layers - MSDN
- WFP Forum - recognize when TCP connection terminated
- Question on MmMapViewInSystemSpace at Osronline
- Tooling around with Vista
- Remote Debugging with VMWare
- How to return the number of elements required for subsequent calls?
- Kernel mode code-signing walkthrough
- Multiple filter conditions not working on Vista
- Poolmon usage
Thursday, June 30, 2011
Palindrome implementation using recursion
int palindrome(node **head, node *cur)
{
int ret = 1;
if (cur) {
ret = palindrome(head, cur->next);
if (cur->data != (*head)->data) {
cout << cur->data << "-" << (*head)->data << ": not a palindrome" << endl;
ret = 0;
}
*head = (*head)->next;
}
return ret;
}
Thursday, June 16, 2011
Calling fopen_s/_wfopen_s with ccs=UNICODE flag
_wfopen_s(&fp, filename, L"w+, ccs=UNICODE");Allowed values of the encoding include UNICODE, UTF-8, and UTF-16LE. If the file is already in existence and is opened for reading or appending, the Byte Order Mark (BOM) is used to determine the correct encoding. It is not necessary to specify the encoding with a flag. In fact, the flag will be ignored if it conflicts with the type of the file as indicated by the BOM. The flag is only used when no BOM is present or if the file is a new file. The following table summarizes the modes used in for various flags given to fopen and Byte Order Marks used in the file.
| Flag | No BOM (or new file) | BOM: UTF-8 | BOM: UTF-16 |
|---|---|---|---|
UNICODE | ANSI | UTF-8 | UTF-16LE |
UTF-8 | UTF-8 | UTF-8 | UTF-16LE |
UTF-16LE | UTF-16LE | UTF-8 | UTF-16LE |
Saturday, June 11, 2011
Priority Queue
typedef int node;
static node *pq;
static int N;
#define swap(a, b) \
do { node tmp = *a; *a = *b; *b = tmp; } while (0)
class prioQ
{
private:
node *pq;
int count;
int max_num;
public:
prioQ(int imax)
{
max_num = imax;
pq = new node[max_num+1];
count = 0;
}
~prioQ()
{
delete pq;
}
int empty()
{
return (count == 0);
}
int insert(node v)
{
if (count >= max_num) {
std::cout << "Queue is full." << std::endl;
return -1;
}
pq[++count] = v;
siftup(pq, count);
return 0;
}
node delmax()
{
if (empty()) {
std::cout << "No more item in the queue." << std::endl;
return -1;
}
swap(&pq[1], &pq[count]);
siftdown(pq, 1, count-1);
return pq[count--];
}
// helper functions from max heap
void siftup(node a[], int k)
{
while ((k > 1) && (a[k] > a[k/2])) {
swap(&a[k/2], &a[k]);
k = k / 2;
}
}
void siftdown(node a[], int k, int end)
{
int i;
while (k*2 <= end) {
i = k * 2;
// k*2 < N is to test one child node case
if ((k*2 < end) && (a[i] < a[i+1])) i++;
if (a[k] > a[i]) break;
swap(&a[k], &a[i]);
k = i;
}
}
};
Sunday, June 5, 2011
sleep() does not put the process to sleep
SYNOPSIS
#includeunsigned int sleep(unsigned int seconds);DESCRIPTION
sleep() makes the current process sleep until seconds seconds
have elapsed or a signal arrives which is not ignored.
At first, I believed this man page but it just happened that I read Jefferey Rithcer's Windows Via C/C++ a few days ago and I remembered that on Windows there is no SuspendProcess() even though there is SuspendThread(). Jefferey explained that it is not quite possible to have SuspendProcess() in that Process can have many threads and these threads can come and go. Hence, it is pretty difficult to get all the threads to be suspended on Windows as thread is a scheduling unit.
Though I am looking at Linux for this particular case, it seems to me that I should check this out with other developers so I posted the question on stackoverflow(http://stackoverflow.com/questions/6192645/does-calling-sleep-from-pthread-put-thread-to-sleep-or-process).
Sure enough, I got an answer that my man page is outdated and I need to report to maintainer of man page to update the man page of my distribution. So the correct description of sleep is as follows. (taken from http://www.kernel.org/doc/man-pages/online/pages/man3/sleep.3.html)
SYNOPSIS
#includeunsigned int sleep(unsigned int seconds);DESCRIPTION
sleep() makes the calling thread sleep until seconds seconds have elapsed or a signal arrives which is not ignored.
So in conclusion, sleep() puts the calling thread to sleep not the process. Interesting!