Load shell process through Process 2, detailed execve

Source: Internet
Author: User
Tags goto signal handler



has always been to execve what exactly do, always make confused, originally look at the design of the Linux kernel art, this part of the explanation is very not meticulous, this combination of Dr. Zhao's book, re-understand this part of the code.



First, the code is listed as follows:




If (!(pid=fork())) {//Process 1 creates process 2
Close(0);
If (open("/etc/rc",O_RDONLY,0))
_exit(1);
Execve("/bin/sh",argv_rc,envp_rc);
_exit(2);
}
Process 1 creates the page directory table for process 2, Process 2, and Page table 1, the page Catalog table entry is the 32nd bit, because the page catalog table is from the kernel 0x0 location, so the page directory entry of Process 2 is 32, because each page catalog entry occupies 4, so the memory address is 128.









Figure 1



At this point, use the command line to view data with a kernel address of 128. 0XFFA027 is the first address of the Process 2 page table.






Figure 2



0xffa000 begins to store the page table entries for process 2, such as:






Figure 3






Here's a look at the real Execve code as follows:





Int do_execve(unsigned long * eip, long tmp, char * filename,
Char ** argv, char ** envp)
{
Struct m_inode * inode;
Struct buffer_head * bh;
Struct exec ex;
Unsigned long page[MAX_ARG_PAGES];//MAX_ARG_PAGES is 32
Int i, argc, envc;
Int e_uid, e_gid;
Int retval;
Int sh_bang = 0;
Unsigned long p=PAGE_SIZE*MAX_ARG_PAGES-4;//4096*32-4=131068=1FFFC

If ((0xffff & eip[1]) != 0x000f)
Panic("execve called from supervisor mode");
For (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
Page[i]=0;
If (!(inode=namei(filename))) // find the i node of /bin/sh
Return -ENOENT;
Argc = count(argv);//number of parameters
Envc = count(envp);//number of environment variables

Restart_interp:
.....
If (!(bh = bread(inode->i_dev, inode->i_zone[0]))) {//Read the data of the first block
Retval = -EACCES;
Goto exec_error2;
}
Ex = *((struct exec *) bh->b_data); //assign to the file header
.....
If (!sh_bang) {
p = copy_strings(envc,envp,page,p,0);
p = copy_strings(argc,argv,page,p,0);//The last returned p is 131068 minus the number of arguments and environment variables, the pointer to the stack. In the current page array, page[31] is already the address of a new application page.
If (!p) {
Retval = -ENOMEM;
Goto exec_error2;
}
}
/* OK, This is the point of no return */
If (current->executable)
Iput(current->executable);
Current->executable = inode;// just got the /bin/sh node
For (i=0 ; i<32 ; i++)
Current->sigaction[i].sa_handler = NULL;//Signal handler is NULL
For (i=0 ; i<NR_OPEN ; i++)//close_on_exec is 0
If ((current->close_on_exec>>i)&1)//will not execute
Sys_close(i);
Current->close_on_exec = 0;
Free_page_tables(get_base(current->ldt[1]), get_limit(0x0f)); //get_base(current->ldt[1]) is 128MB, get_limit(0x0f) is 640KB, and the 32nd entry of the page directory entry is cleared. The page table it points to is also cleared.
Free_page_tables(get_base(current->ldt[2]), get_limit(0x17));
If (last_task_used_math == current)
Last_task_used_math = NULL;
Current->used_math = 0;
p += change_ldt(ex.a_text,page)-MAX_ARG_PAGES*PAGE_SIZE;//p last PAGE_SIZE*MAX_ARG_PAGES-4 - number of bytes of parameters and environment variables + 64MB - MAX_ARG_PAGES*PAGE_SIZE, and finally 64MB-4-
The number of bytes of parameters and environment variables, that is, replaced with a stack value of 64MB.
p = (unsigned long) create_tables((char *)p,argc,envc);
Current->brk = ex.a_bss +(current->end_data = ex.a_data +(current->end_code = ex.a_text));//code segment, data segment, bss segment
Current->start_stack = p & 0xfffff000;
Current->euid = e_uid;
Current->egid = e_gid;
......
Eip[0] = ex.a_entry; //The eip that the kernel stack wants to return to user space
Eip[3] = p; //the kernel stack uses the esp returned to user space
Return 0;
....
Return(retval);
}




1, Inode=namei (filename), find the/bin/sh i node.


2, argc = count (argv); ENVC = count (ENVP), calculates the number of parameters and environment variables.



3, BH = bread (inode->i_dev,inode->i_zone[0]), ex = * ((struct exec *) bh->b_data), find the/bin/sh file header.






Below is Copy_strings (envc,envp,page,p,0). The code is as follows:




Static unsigned long copy_strings(int argc,char ** argv,unsigned long *page,
Unsigned long p, int from_kmem)
{
Char *tmp, *pag=NULL;
Int len, offset = 0;
Unsigned long old_fs, new_fs;

If (!p)
Return 0; /* bullet-proofing */
New_fs = get_ds();
Old_fs = get_fs();
.....
While (argc-- > 0) {//Number of parameters
.....
If (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc)))) / / pointer to the first parameter
Panic("argc is wrong");
.....
Len=0; /* remember zero-padding */
Do {
Len++;
} while (get_fs_byte(tmp++));//Get the length of the first argument
If (p-len < 0) { /* this shouldn‘t happen - 128kB */
Set_fs(old_fs);
Return 0;
}
While (len) {
--p; --tmp; --len;
If (--offset < 0) {// first enter offset to -1
Offset = p % PAGE_SIZE; / / offset is 4092
......
If (!(pag = (char *) page[p/PAGE_SIZE]) && //p/PAGE_SIZE is 31
!(pag = (char *) page[p/PAGE_SIZE] =
(unsigned long *) get_free_page())) //page[31] stores the address of the new application page
Return 0;
.....

}
*(pag + offset) = get_fs_byte(tmp);// With the loop, the parameters are written to the newly requested page (from 4092 to the lower address 4091, 4090.....)
}
}
        ......
Return p; / / finally returned 131068 - the byte of the parameter, the pointer to the stack.
}
Since From_kmem is 0, we remove the case where the FROM_KMEM is a different value.





The meaning of the parameter is as follows: P is the number of 131068,ARGC bit parameters, AGRV is an array of pointers to parameters, page is the first address of page[max_arg_pages].



We assume that only one page has been applied to save parameters and environment variables, and the last P returned is 131068 minus the number of arguments and environment variables, the stack pointer. In the current page array, page[31] is already the address of a new application page.






The following analysis, Free_page_tables code, is as follows:




Int free_page_tables(unsigned long from, unsigned long size)//from is 128MB, size is 640KB
{
Unsigned long *pg_table;
Unsigned long * dir, nr;

If (from & 0x3fffff)
Panic("free_page_tables called with wrong alignment");
If (!from)
Panic("Trying to free up swapper memory space");
Size = (size + 0x3fffff) >> 22;//size is 1
Dir = (unsigned long *) ((from>>20) & 0xffc); //dir is 128
For ( ; size-->0 ; dir++) {
If (!(1 & *dir))
Continue;
Pg_table = (unsigned long *) (0xfffff000 & *dir); / / pg_table is the memory address pointed to by the 32nd entry of the page directory entry
For (nr=0 ; nr<1024 ; nr++) {
If (1 & *pg_table)
Free_page(0xfffff000 & *pg_table);//mem_map corresponding to the bit minus 1, may be cleared to 0, can be reused for allocation
*pg_table = 0; / / corresponding page table entries are cleared
Pg_table++;
}
Free_page(0xfffff000 & *dir);//Because the address is less than 1MB, it returns directly
*dir = 0; / / 32nd page directory entry page clear
}
Invalidate();
Return 0;
}
Free_page, the code is as follows:






void free_page(unsigned long addr)
{
	if (addr < LOW_MEM) return;//1MB以上
	if (addr >= HIGH_MEMORY)
		panic("trying to free nonexistent page");
	addr -= LOW_MEM;
	addr >>= 12;
	if (mem_map[addr]--) return;//mem_map对应的位减1
	mem_map[addr]=0;
	panic("trying to free free page");
}
Free_page_tables, the 32nd item of the page catalog is zeroed, and the page table it points to is 0 clear.









Figure 4






Here's a look at Change_ldt, the code below:




Static unsigned long change_ldt(unsigned long text_size,unsigned long * page)
{
Unsigned long code_limit, data_limit, code_base, data_base;
Int i;

Code_limit = text_size+PAGE_SIZE -1; //text_size is the length of the shell snippet
Code_limit &= 0xFFFFF000; / / the boundary of the code segment is the length of the shell code segment
Data_limit = 0x4000000; / / the limit of the data segment is 64MB
Code_base = get_base(current->ldt[1]);//The code base base address is 128MB
Data_base = code_base; / / data segment base address is 128
Set_base(current->ldt[1],code_base);//Modify the code segment base address is 128MB
Set_limit(current->ldt[1],code_limit);//Modify the code segment boundary to the length of the shell code segment
Set_base(current->ldt[2],data_base);//Modify the data segment base address is 128MB
Set_limit(current->ldt[2],data_limit);//Modify the data segment boundary to 64MB
/* make sure fs points to the NEW data segment */
__asm__("pushl $0x17\n\tpop %%fs"::);
Data_base += data_limit;//192MB
For (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) {//MAX_ARG_PAGES is 31
Data_base -= PAGE_SIZE; / / data_base is 192MB-4096B
If (page[i]) / / now only page [31] has an address, which stores the first address of the page of parameters and environment variables
Put_page(page[i],data_base);
}
Return data_limit; / / return 64MB
}
Change_ldt, the base address and segment bounds of the code snippet and data segment are modified, the segment bounds of the data segment is 64MB, and because a page catalog entry can represent a 4MB memory address, 16 page catalog entries are required. That is, from the 32nd page of the catalog item to the 48th page Catalog item.








Here's a look at Put_page, the code below:


Unsigned long put_page(unsigned long page,unsigned long address)//address is 0xBFFF000
{
Unsigned long tmp, *page_table;

/* NOTE !!! This uses the fact that _pg_dir=0 */

If (page < LOW_MEM || page >= HIGH_MEMORY)
Printk("Trying to put page %p at %p\n",page,address);
If (mem_map[(page-LOW_MEM)>>12] != 1)
Printk("mem_map disagrees with %p at %p\n",page,address);
Page_table = (unsigned long *) ((address>>20) & 0xffc);//BxBC, is 188
If ((*page_table)&1)// is currently 0
Page_table = (unsigned long *) (0xfffff000 & *page_table);
Else {//going here
If (!(tmp=get_free_page()))//Get the page table of the page table entry
Return 0;
*page_table = tmp|7;//Page Table Table 188 holds the page table address just obtained
Page_table = (unsigned long *) tmp; / / assign the page table address to page_table
}
Page_table[(address>>12) & 0x3ff] = page | 7;// The last item in the page table is the page (the first address of the page where the parameters and environment variables are stored)
/* no need for invalidate */
Return page;
}
Put_page,address for 0xbfff000,page for PAGE[31], storing the parameters and environment variables for the first address of the page. After executing the put_page, the memory figure is as follows:








The 48th bit of the page catalog entry, pointing to the first address of the page table. The first address of the page table +4092, this address is the content of the stored parameters and environment variables of the first address of the page.






p + = Change_ldt (ex.a_text,page)-max_arg_pages*page_size;//p last for page_size*max_arg_pages-4-the number of bytes of parameters and environment variables + 64mb-max_arg _pages*page_size, the last is the number of bytes of the 64mb-4-parameter and environment variable, which is replaced by a stack value of 64MB.






Then call Create_tables with the following code:




static unsigned long * create_tables(char * p,int argc,int envc)
{
	unsigned long *argv,*envp;
	unsigned long * sp;

	sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
	sp -= envc+1;
	envp = sp;
	sp -= argc+1;
	argv = sp;
	put_fs_long((unsigned long)envp,--sp);
	put_fs_long((unsigned long)argv,--sp);
	put_fs_long((unsigned long)argc,--sp);
	while (argc-->0) {
		put_fs_long((unsigned long) p,argv++);
		while (get_fs_byte(p++)) /* nothing */ ;
	}
	put_fs_long(0,argv);
	while (envc-->0) {
		put_fs_long((unsigned long) p,envp++);
		while (get_fs_byte(p++)) /* nothing */ ;
	}
	put_fs_long(0,envp);
	return sp;
}

Finally formed such as:











The final finishing touches,




Eip[0] = ex.a_entry; //The eip that the kernel stack wants to return to user space
Eip[3] = p; //the kernel stack uses the esp returned to user space 
EIP is 0,esp for 64mb-4-parameters and environment variables, that is, in user space, access to SS:EIP, is to access the 128mb+64mb-4-parameters and environment variables of the number of bytes, after paging mechanism, Finally, you have access to the specified location of the page where the parameters and environment variables are ultimately stored.





Load shell process through Process 2, detailed execve


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.