VC程序的SECTION(3):.text


快乐虾

http://blog.csdn.net/lights_joy/

[email protected]

 

本文适用于

Xp sp3 / Vs2008

  

欢迎转载,但请保留作者信息

 

这个节看起来很容易理解,不就是存放代码的嘛,看看头信息:

SECTION HEADER #2

   .text name

    3482 virtual size

   11000 virtual address (00411000 to 00414481)

    3600 size of raw data

     400 file pointer to raw data (00000400 to 000039FF)

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

60000020 flags

         Code

         Execute Read

比较.textbss可以看到这一节是只读的,但.textbss则是可以读写的。

下面讨论一下几个比较有意思的问题。

1.1.1   ILT表

查看符号表,可以发现从.text节的开始到第一个函数代码中间有一段空间:

0002:000003a0       ?add@@YAHHH@Z              004113a0 f   demo.obj

根据.textbss节中获取的信息,我们可以知道当启用增量链接时,这一段空间用于存放ILT表。

1.1.2   DLL中的函数

在符号表中还有这样一些有趣的符号:

0002:000024e2       _GetCurrentProcessId@0     004134e2 f   kernel32:KERNEL32.dll

 0002:000024e8       _GetSystemTimeAsFileTime@4 004134e8 f   kernel32:KERNEL32.dll

这些函数应该是在DLL中实现的,为何会出现符号表中呢?而且每个函数都只有6个字节,在反汇编中看看到底是什么:

GetCurrentProcessId:

004134E2  jmp         dword ptr [__imp__GetCurrentProcessId@0 (4181BCh)]

GetSystemTimeAsFileTime:

004134E8  jmp         dword ptr [__imp__GetSystemTimeAsFileTime@4 (4181B8h)]

又是jmp,又是ILT?关闭增量链接,再看这段地址,依然存放,很不幸地猜想失败。

 

在函数中加上对此函数的调用,在符号表中可以看到GetCurrentProcessId的地址发生了变化:

0002:00000446       _GetCurrentProcessId@0     00411446 f   kernel32:KERNEL32.dll

但反汇编的结果显示它的内容并没有变化:

GetCurrentProcessId:

00411446  jmp         dword ptr [__imp__GetCurrentProcessId@0 (418198h)]

 

再看调用者的反汇编代码:

     int n = GetCurrentProcessId();

004113FE  mov         esi,esp

00411400  call        dword ptr [__imp__GetCurrentProcessId@0 (418198h)]

00411406  cmp         esi,esp

00411408  call        @ILT+315(__RTC_CheckEsp) (411140h)

0041140D  mov         dword ptr [n],eax

这里直接调用的是__imp__GetCurrentProcessId@0函数,那么为什么还要生成前面那个jmp代码呢?据说这个问题深究起来比较复杂,先放过它,到DLL中学习它。

1.1.3   自定义节

使用

#pragma code_seg("code1")

可以自定义一个code section,节的名字就是code1,需要注意的是这个语句的作用范围为当前文件。

试试看:

#pragma code_seg("code1")

 

int add(int a, int b)

{

     return a + b + 10;

}

 

int _tmain(int argc, _TCHAR* argv[])

{

     add(3, 4);

     return 0;

}

用dumpbin查看生成的头信息,发现多了一个节:

SECTION HEADER #1

   code1 name

      77 virtual size

    1000 virtual address (00401000 to 00401076)

     200 size of raw data

     400 file pointer to raw data (00000400 to 000005FF)

       0 file pointer to relocation table

       0 file pointer to line numbers

       0 number of relocations

       0 number of line numbers

60000020 flags

         Code

         Execute Read

 

对照符号表中这一节的符号:

0001:00000000       ?add@@YAHHH@Z              00401000 f   demo.obj

0001:00000030       _main                      00401030 f   demo.obj

非常符合我们的期望。

1.1.4   改变节中函数的顺序

下面尝试改变code1节中main函数与add函数的顺序。

在code1这个节名称的后面加上尾缀:

 

 

#pragma code_seg("code1$b")

int add(int a, int b)

{

     return a + b + 10;

}

 

#pragma code_seg("code1$a")

int _tmain(int argc, _TCHAR* argv[])

{

     add(3, 4);

     return 0;

}


VS将$之前的部分视为节的名称,再根据$后的字母进行排序。

再看生成的符号表:

0001:00000000       _main                      00401000 f   demo.obj

0001:00000040       ?add@@YAHHH@Z              00401040 f   demo.obj

符合我们的期望。

当不加$及之后的尾缀时,默认放在最前。

利用链接器的这种特性,我们很容易就可以获取一个节的起始位置和结束位置。

1.1.5   获取.text节的起始地址

.text用于默认存放代码,VS并没有象GNU TOOLCHAIN那样提供链接器的符号,因而只有自己动态查询,就像这样的:

     PIMAGE_FILE_HEADER pfh;

     PIMAGE_OPTIONAL_HEADER poh;

     PIMAGE_SECTION_HEADER psh;

     HMODULE hModule;

     MODULEINFO modinfo;

     DWORD dwBase, cbNeeded;

     BYTE* lpbuf;

     HANDLE hProcess = ::GetCurrentProcess();

     EnumProcessModules(hProcess,   &hModule,   sizeof(HMODULE),   &cbNeeded);

     GetModuleInformation( hProcess, hModule, &modinfo, sizeof(MODULEINFO) );

 

     // 根据lpBaseOfDll得到其它的数据

     lpbuf = (BYTE*)modinfo.lpBaseOfDll;

 

     //取得节数目

     pfh   =   (PIMAGE_FILE_HEADER)   ((LPVOID)((BYTE *)(lpbuf)+((PIMAGE_DOS_HEADER)(lpbuf))-> e_lfanew+sizeof(DWORD)));

     int nSectionCount   =   pfh-> NumberOfSections;

 

     poh = (PIMAGE_OPTIONAL_HEADER)(pfh + 1);

     psh   =   (PIMAGE_SECTION_HEADER)   ((LPVOID)((BYTE   *)pfh + sizeof(IMAGE_FILE_HEADER) + pfh->SizeOfOptionalHeader));

    

     dwBase = 0;

     for(int i = 0; i < nSectionCount; i++)

     {

         if(strcmp( ".text",   (char *)psh->Name) == 0)

         {

              dwBase = (DWORD)modinfo.lpBaseOfDll + psh->VirtualAddress;

         }

         psh++;

     }

 

 

 

 

 

 

你可能感兴趣的:(汇编,header,File,dll,byte,Numbers)