分类 技术 下的文章

exe,dll,sys,com为主流可执行文件格式(pe格式)
32位pe32 64位pe32+
winnt.h有pe详细定义
pe含程序运行时所有info

layout:

ms-dos header
nt header
section header
section 实体

MS-DOS Header

DOS MZ Header
DOS STUB

IMAGE NT HEADERS

Signature
IMAGE FILE HEADERS
IMAGE
_OPTIONAL HEADERS
IMAGE DATA DIRECTORY(array lists)

Section Table

IMAGE SECTION HEADER
......
IMAGE SECTION HEADER

Sections

SECTION
SECTION
......
SECTION

实现LoadLibrary(系统默认给的pe格式),PE文件加载到内存中经过四步

  1. 要判定输入文件是否是PE格式;
  2. 要将PE文件分块按照内存映像结构放在内存中;
  3. 在IAT(Import Address Table)中,填入其依赖的导入函数地址
  4. 利用重定位表修复需要重定位的值。

PE文件加载,首先要检查的是该文件是否为PE格式,还需要检查该PE文件是否为DLL。
◎ PE的检测,需要检查的部分是MS-DOS头和NT头
◎ DLL的检测(只针对dll),检查NT头中的IMAGE_FILE_HEADER.

MS-DOS头
◎ MS-DOS头是微软为了考虑PE文件对DOS文件的兼容性而添加的。
• 大多数情况下由编译器自动生成,通常把
DOS MZ头与DOS stub合称为DOS文件头
◎ IMAGE_DOS_HEADER结构体如下图

IMAGE DOS HEADER结构体共64字节,其中两个字段比较重要,分别是e_magic
e_lfanew.

byte 1字节 word 2字节 double word 4字节

e_magic: 4D5A=>MZ 代表DOS signature
e_lfanew: NT offset address

Signature字段必须被设置为0x00004550

其中Machine,NumberOfSections,SizeOfOptionalHeader, Characteristics如果出现错误,将导致该PE文件无法正常执行。

0#1 Machine
◎该字段说明了可执行文件的目标CPU类型。
常见的一些Machine码
Machine Value
Inteli386 14Ch
MIPS R3000 162h
MIPS R4000 166h
Alpha AXP 184h
Power PC 1F0h

2 NumberOfSections

◎该字段说明了在这个PE文件中节区(Section)的数目。

3 TimeDateStamp

◎该字段说明了该PE文件是何时被创建的。

4 PointerToSymbolTable

◎该字段说明了COFF符号表(基本用不到)的文件偏移位置。COFF符号表在PE文件中较为少见,通常其值为0

SizeOfOptionalHeader
对于32位文件,该字段通常为0x00E0
对于64位文件,该字段通常为0x00F0

Magic
当IMAGE_ OPTIONAL_HEADER为
IMAGE_OPTIONAL_HEADER32(32位)时,Magic
0x10B。当其为IMAGE_OPTIONAL_HEADER64时,
Magic)70x20B.

AddressOfEntryPoint
该字段的值相对虚拟地址(加载到内存的地址),该值表明了程序最先执行的代码的启始地址,即程序入口点。

ImageBase
该字段表明了PE文件被加载进内存时,文件将被优先装入的虚拟内存的地址。对于EXE来说,ImageBase通常为0x00400000;对于DLL来说,ImageBase通常为0x10000000。装载后,EIP = ImageBase+
AddressOfEntryPoint.

SectionAlignment,FileAlignment
PE文件的Body部分划分为若干节区,FileAlignment制定了节区在文件系统中的最小单位,SectionAlignment则指定了节区在内存中的最小单位。
磁盘文件或内存的节区大小必定为FileAlignment或SectionAlignment的整数倍。

SizeOflmage
加载PE文件时,SizeOflmage指定了PE Image在虚拟内存中所占的空间大小。

SizeOfHeaders
该字段表明了整个PE文件头部的大小,该值必须是FileAlignment的整数倍。

Subsystem
该字段用于区分系统驱动文件与普通可执行文件。

NumberOfRvaAndSizes
该字段表明了下面出现的DataDirectory数组的个数。一般来说该值为16。

DataDirectory
DataDirectory是有IMAGE_DATA_DIRECTORY结构体构成的数组,数组的每项都有不同的意义。

RVA&VA(OS referance:ostep)
relative virtual address
virtual address(va)

va=image base + rva

PE文件在存储时为了减少体积,FileAlignment通常小于SectionAlignment。
当文件被映射到内存中后,同一数据在文件中的偏移量与在内存中的偏移量是不一样的,这样就存在这从文件偏移地址(RAW)到相对虚拟地址(RVA)之间的转换。
如果需要对存储在硬盘中的PE文件进行操作,需要将RVA换为RAW。

高级ASA防火墙特点:

  • 虚拟化
  • 高可用性(设备链路冗余)
  • 鉴定权限(基于IP)
  • 威胁控制(AIP,AIP-SSM,AIP-SSC)

outside
inside(ban outside&DMZ)
DMZ-非军事区

运行模式:
Annotation.png

[do] show activation-key # 验证许可证

安全级别:用于区分内/外部网络,代表接口可信度指标
每个运行的接口必须分配 名字 + 安全级别
0(最低)-100(最高)

1.png

stat结构体如下:

struct stat:
dev_t        st_dev        /*id device containing file*/
ino_t        st_ino        /*inode number*/
mode_t        st_mdoe        /*protection*/
nlink_t        st_nlink    /*number of hard link*/
uid_t        st_uid        /*user id of owner*/
gid_t        st_gid        /*group id of owner*/
dev_t        st_rdev        /*device ID(if specical file)*/
off_t        st_size        /*total size in bytes*/
blksize_t    st_blksize    /*blocksize for filesystem I/O*/
blkcnt_t    st_blokcs    /*number of blocks allocated*/
time_t        st_atime    /*time to last access*/
time_t        st_mtime    /*time to last modification*/
time_t        st_ctime    /*time to last satus change*/

struct stat常用字段:

st_mode:文件的访问权限和文件类型。您可以使用宏(如 S_ISREG()、S_ISDIR())来检查文件类型和权限。
st_size:文件的大小(以字节为单位)。
st_uid:文件所有者的用户ID。
st_gid:文件所属组的组ID。
st_atime:最后访问时间(上次读取文件的时间)。
st_mtime:最后修改时间(上次修改文件的时间)。
st_ctime:文件状态改变时间(上次修改文件权限、所有者等的时间)。

自定义命令的显示写法(开源项目里命令使用提示类似linux那种自带提示):

if(argc != 2){printf("Usage : stat <pathname>\n");exit(-1);}

argc处的2可以为任意num,判断的是用户输入的参数是否数量对应,不对应就显示Usage提示并退出

实例

综上,可以写出类ls命令的自定义stat命令实例,代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>

int main(int argc,char ** argv)
{
  struct stat buf;
  
  if(argc != 2){
  printf("Usage : stat <pathname>\n");exit(-1);
    }
  if(stat(argv[1],&buf) != 0){
  printf("stat error!\n");exit(-1);
 }
  printf("#DEV_ID       :\n",(int)buf.st_dev);
  printf("#i-node       :\n",(int)buf.st_ino);
  printf("#link         :\n",(long)buf.st_nlink);
  printf("#UID          :\n",(int)buf.st_uid);
  printf("#GID          :\n",(int)buf.st_gid);
  printf("#size         :\n",(long)buf.st_size);
  printf("#modify_time  :\n",(long)buf.st_mtime);
  printf("#change_time  :\n",(long)buf.st_ctime);
  exit(0);
    }

在linux项目中,源码的编译一般分为手动和自动,两种方法都是基于gcc实现的。但在修改和重新编译的便捷程度上来说,手动不如自动,而自动编译一般是基于makefile来实现的编译。

makefile尤其是在中大型C Project中是非常有用的,实现了代码修改和编译的解耦合。实例如下:

code.c

//code.c
#include "code.h"
int myfun(int in){
  return in + 1;
}

code.h

//code.h
extern int myfun(int);

prog.c

//prog.c
#include<stdio.h>
#include "code.h"
int main(void){
  int i = 1;
  printf("myfun(i) = %d\n",myfun(i));
}

如上实例其实比较简单,手动编译的话其实也只需要三行命令实现,如下:

gcc -c code.c -o code.o
gcc -c prog.c -o prog.o
gcc prog.o code.o -o test

但是如果我们通过makefile,其实可以只通过更为简短好记的命令完成编译:

Makefile

test: prog.o code.o
    gcc prog.o code.o -o test
    ./test
prog.o: prog.c code.h
    gcc -c prog.c -o prog.o
code.o: code.c code.h
    gcc -c code.c -o code.o
clean:
    rm -f *.o test

命令:

make test    //实现编译并运行
make clearn    //清除中间文件和编译后的可执行文件

通过比较手动和自动,不难发现基于makefile的自动编译省去了敲命令的时间,还减少了gcc命令的输入错误和输入时间,有助于后期项目的修改和维护。

详解Makefile文件逻辑

makefile的撰写逻辑其实是非常清晰的,想象有一颗倒过来的树,树的顶端就是你最终想要实现的可运行的文件,而依次往下就是你要编译的文件,得到的图解就会如下图所示:(基于上面的实例做示范)

make工作树
借助工作树,可以帮助你更好的理解项目的依赖和编译过程.与此同时它也可以辅助你快速的写出项目的makefile文件实现项目的自动编译。

通过上面的工作树,我们可以得知:makefile里每一次编译动作的执行都需要两个参数(clean动作除外),如:
test: prog.o code.o
对此再进一步总结,就可以得出格式如下:

目标文件:    依赖文件列表
TAB命令
...
TAB命令
...

拓展

以上只是最简单和最基础的makefile的使用,进阶可以参考:
Makefile入门(超详细一文读懂)
全网最牛Linux内核Makefile文件详解