6月15日所得所感

         周一,又是个无比忧伤的日子。学长学姐忙着毕业,倍儿开心,然而我们却要开始继续日复一日年复一年的烟酒僧生活,damn it!

       早上来了就开始忙着看学长的代码,真是难受!但是昨晚好像做了个春梦,感觉爽爽的……

       早上主要看的代码是之前虚拟机跑僵尸程序那块,大体是读取一个input文件,得到僵尸程序可执行文件,然后使用shellexecute调用可执行文件,通过抓取僵尸程序运行过程中产生的流量并保存。该文件主要用来得到黑名单,从而用于僵尸网络检测系统黑名单匹配模块。因为之前就能正常运行,但是有些不能解决的bug,所以要从头仔细慢慢看。卧槽,不看不知道,一看吓一跳。各种不靠谱,各种不严谨,各种乱七八糟。我真是曰了狗了,他们之前的实验是怎么做的,我在想。下面主要就自己解决的几个问题来总结下。

       1、首先,因为虚拟机进程不能正常kill。之前师兄老是说虚拟机运行一段时间后就会死机,这就是会死机的原因啊!你进程一直kill不掉,到一定时间机器怎么能hold住?!换一个人一直长时间负荷运转,也吃不消啊……之前学长的代码是这样进行进程的kill的:

hProcess=OpenProcess(PROCESS_ALL_ACCESS,FALSE,cpList[i]);
if(hProcess==NULL)
{
printf("error opening process!\n");
return ;
}
if(!TerminateProcess(hProcess,0))
{
printf("error killing process!\n");
return ;
}

其中OpenProcess的原型及用法有:

http://baike.baidu.com/link?url=zVaohX3FXM3NWgbO0j2g54WzFcmhtADfNlUiWTmcplACmE39bm0wQbqqZS4yds6yyK5ZJUyd__Y9bf_OzW4Cu_

OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄。
1.函数原型
HANDLE OpenProcess(
DWORD dwDesiredAccess, //渴望得到的访问权限(标志)
BOOL bInheritHandle, // 是否继承句柄
DWORD dwProcessId// 进程标示符
);

 获取到进程号之后,然后进行进程的kill。上网查了方法,这种方法是可行的,但是为什么进程就是kill不掉呢?!为了直观地显示进程是否kill,我比较了hellexecute调用可执行代码的前与后的进程序列,发现真正地没有对多出来的进程进行kill。那为什么在VS上调试可运行并且起作用,但到了这里就不可以了呢?!第一感觉就是,虚拟机环境的问题。然后直接上网百度了,发现确实存在这样的问题。相关链接为:

https://social.msdn.microsoft.com/Forums/zh-CN/20e3fc99-1d21-43b5-9bc2-03a52a721dc5/openprocess?forum=visualcpluszhchs

把上面第一部分的代码加入到之前我们的代码中,发现程序可以按照我们预想的那样去运行。此外,之前运行的system指令也可以正常运行了。原来虚拟机上的处理与实体机处理还是不相同的,存在着权限提取问题。

所添加的这部分代码如下,以后可能还会用到。

void EnableDebugPriv() 

HANDLE hToken;
LUID sedebugnameValue; 
TOKEN_PRIVILEGES tkp; 


if ( ! OpenProcessToken( GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken ) ) 
{
printf("提权失败。\n");
return; 
}


if ( ! LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &sedebugnameValue ) ) 

CloseHandle( hToken ); 
printf("提权失败。\n");
return; 

tkp.PrivilegeCount = 1; 
tkp.Privileges[0].Luid = sedebugnameValue; 
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 
if ( ! AdjustTokenPrivileges( hToken, FALSE, &tkp, sizeof tkp, NULL, NULL ) ) 
{
printf("提权失败。\n");
CloseHandle( hToken );
}
else 
printf("提权成功!\n");
}

至此,虚拟机那边调用僵尸可执行文件的程序可以按照我预想的那样正常运行,算了屌了一把……忍不住要夸自己就是个天才! 

       下午的时候,潘博过来找人写一个组流的程序,讲了大致要实现的功能。因为研三的那些人都忙着给老板提交演示,没人有时间搭理他。但是听了潘博所要求的功能后,土豪忽然回忆起来之前他有叫我写过一个类似的程序。然后我就试着给潘博改代码。因为类似,很快就改好了……但是,不能用!因为之前只要80端口的流量,所以做map匹配的时候很简单,但是现在是要求五元组用来做map的key,原理其实差不多,只是有些细节要处理。首先想着用map来做记录的保存。其中,

struct mapvalue

{
       pcap_dumper_t *pc;  //pcap文件的句柄
       time_t tm_sec;           //时间,因为需要判断流超时
};

但是程序跑起来之后,不能正常地区分不同的char *。就是对一个pcap文件进行处理后,最后得到的还是一个文件,这肯定不对!想了好一会,不知道原因。后来,换用

map 结构。本来之前就想用这个结构,因为最近在刷leetcode,习惯了用string之类的。但是有个地方让我很难受,就是得到map中的key的string变量时,不能像sprintf(file_tagger,"%u%u%u%u",sIP,dIP,sPort,dPort)这样将其输入到file_tagger中去(如果file_tagger是char *的话,就可以了)。就是因为这个就想回避这样,但是后来程序不能正常运行,只能试试这种方法。这里就涉及到字符串的拼接了,直接使用+便可以。但是像sIP,dIP,sPort,dPort之类的,不是u_int32_t就是u_int16_t ,这便需要将它们转换成string类型。这里便是itoa的问题了,对这个函数不怎么熟,上网查了用法,试着用了,但是可能include的问题不能正常编译通过。后来想想,干嘛要调用itoa()。本来就是个弱功能的函数,自己实现也行。根据网上的代码,自己再修改下,最后为:

void my_itoa(u_int32_t value,string &dst,int radix)  
{   
    char tmp[32]={'\0'};  
    u_int32_t tmpval=value;  
    int i,j;  
    for(i=0;i<32;i++)  
    {                  
              tmp[i]=(tmpval%radix)+'0'; 
              tmpval=tmpval/radix;  
              if(tmpval==0)  
                     break;  
    }
       for(;i>=0;--i)
       {
              dst=dst+tmp[i];
       } 
}  

很弱,不值得一提。下面我就可以使用连接符+从而获得能够标示一段流的map的key的string。

这个map的功能实现后,下面主要就是读取pcap包,并将其按照五元组分别放到不同的pcap包中。由于涉及到超时问题,所以就需要一个时间标记来注明,在之前的struct mapvalue中也予以说明。这里需要说明的是,之前一直以为map的值不能够使用结构体,经过这次之后,发现这种想法是不对的。完全可以使用结构体作为map的second值!

经过上面的修改后,程序便可以正常运行,但是得到的结果文件中数量太大,而且很多都是小文件。跟潘博商量程序结果后,便决定将一些比较小的文件予以删除。对pcap包的处理,需要对pcap文件格式有很好的了解,这对学网络数据包处理来说,是必须要去掌握的。此外,还需要对pcap data里面各层数据的解析需要对以太层、IP层以及各种上层协议的理解。总的来说,主要用到了两个知识点,根据网上的一些代码,整理如下:

1、Linux C读取文件夹下所有文件(包括子文件夹)的文件名

Linux C  下面读取文件夹要用到结构体struct dirent,在头#include 中,如下:

#include

struct dirent

{

   long d_ino; /* inode number 索引节点号 */

   off_t d_off; /*offset to this dirent在目录文件中的偏移 */

   unsigned shortd_reclen;/* length of this d_name 文件名长 */

   unsigned chard_type;/* the type of d_name 文件类型 */

   char d_name[NAME_MAX+1];/*file name (null-terminated) 文件名,最长255字符 */

}

其中d_type表明该文件的类型:文件(8)、目录(4)、链接文件(10)等。

 

下面程序,递归读取某文件夹及其子文件夹下所有文件名:

 1 #include

 2 #include

 3 #include <string.h>

 4 #include

 5 #include

 6 int readFileList(char*basePath)

 7 {

 8     DIR *dir;

 9     structdirent *ptr;

10     char base[1000];

11

12     if ((dir=opendir(basePath)) == NULL)

13     {

14         perror("Open dir error...");

15         exit(1);

16     }

17

18     while ((ptr=readdir(dir)) != NULL)

19     {

20         if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0)   ///current dir OR parrentdir

21             continue;

22         else if(ptr->d_type== 8)   ///file

23            printf("d_name:%s/%s\n",basePath,ptr->d_name);

24         else if(ptr->d_type== 10)   ///link file

25            printf("d_name:%s/%s\n",basePath,ptr->d_name);

26         else if(ptr->d_type== 4)   ///dir

27         {

28            memset(base,'\0',sizeof(base));

29            strcpy(base,basePath);

30             strcat(base,"/");

31            strcat(base,ptr->d_name);

32            readFileList(base);

33         }

34     }

35    closedir(dir);

36     return 1;

37 }

38

39 int main(void)

40 {

41     DIR *dir;

42     char basePath[1000];

43

44     ///get the current absoultepath

45    memset(basePath,'\0',sizeof(basePath));

46    getcwd(basePath,999);

47     printf("the current dir is : %s\n",basePath);

48

49     ///get the file list

50    memset(basePath,'\0',sizeof(basePath));

51     strcpy(basePath,"./XL");

52    readFileList(basePath);

53     return 0;

54 }

执行输出 :

2、linux下C获取文件的大小

获取文件大小这里有两种方法:

方法一、

范例:

[cpp] view plaincopyprint?

  1. unsigned long get_file_size(const char *path)  
  2. {  
  3.     unsigned long filesize = -1;  
  4.     FILE *fp;  
  5.     fp = fopen(path, "r");  
  6.     if(fp == NULL)  
  7.         return filesize;  
  8.     fseek(fp, 0L, SEEK_END);  
  9.     filesize = ftell(fp);  
  10.     fclose(fp);  
  11.     return filesize;  
  12. }  
  13.   
  14.       

  

 

此种以打开文件的方法取得文件的大小,不适合大文件,并且可能会出现访问冲突(比如正在下载的文件),效率也比较低

 

方法二、

 范例:

[c-sharp] view plaincopyprint?

  1. #include   
  2.   
  3. unsigned long get_file_size(const char *path)  
  4. {  
  5.     unsigned long filesize = -1;      
  6.     struct stat statbuff;  
  7.     if(stat(path, &statbuff) < 0){  
  8.         return filesize;  
  9.     }else{  
  10.         filesize = statbuff.st_size;  
  11.     }  
  12.     return filesize;  
  13. }  

 需要注意的是:filesize的单位是字节!

此种使用读取文件属性的方法得到文件的大小,效率较高,也较稳定

 

 

下面将stat的详细信息粘贴出来:

 

stat(取得文件状态)     
相关函数     fstat,lstat,chmod,chown,readlink,utime 
  
表头文件     #include  
#include  
  
定义函数     int   stat(const   char   *  file_name,struct   stat   *buf); 
  
函数说明     stat()用来将参数file_name所指的文件状态,复制到参数buf所指的结构中。 
下面是struct   stat内各参数的说明 
struct   stat 

dev_t   st_dev;   /*device*/ 
ino_t   st_ino;   /*inode*/ 
mode_t   st_mode;   /*protection*/ 
nlink_t   st_nlink;   /*number   of   hard  links   */ 
uid_t   st_uid;   /*user   ID   of  owner*/ 
gid_t   st_gid;   /*group   ID   of  owner*/ 
dev_t   st_rdev;   /*device   type   */ 
off_t   st_size;   /*total   size,   in  bytes*/ 
unsigned   long   st_blksize;   /*blocksize   for  filesystem   I/O   */ 
unsigned   long   st_blocks;   /*number   of  blocks   allocated*/ 
time_t   st_atime;   /*   time   of  lastaccess*/ 
time_t   st_mtime;   /*   time   of   last  modification   */ 
time_t   st_ctime;   /*   time   of   last  change   */ 
}; 
st_dev   文件的设备编号 
st_ino   文件的i-node 
st_mode   文件的类型和存取的权限 
st_nlink   连到该文件的硬连接数目,刚建立的文件值为1。 
st_uid   文件所有者的用户识别码 
st_gid   文件所有者的组识别码 
st_rdev   若此文件为装置设备文件,则为其设备编号 
st_size   文件大小,以字节计算 
st_blksize   文件系统的I/O   缓冲区大小。 
st_blcoks   占用文件区块的个数,每一区块大小为512   个字节。 
st_atime   文件最近一次被存取或被执行的时间,一般只有在用mknod、utime、read、write与tructate时改变。 
st_mtime   文件最后一次被修改的时间,一般只有在用mknod、utime和write时才会改变 
st_ctime   i-node最近一次被更改的时间,此参数会在文件所有者、组、权限被更改时更新先前所描述的st_mode   则定义了下列数种情况 
S_IFMT   0170000   文件类型的位遮罩 
S_IFSOCK   0140000   scoket 
S_IFLNK   0120000   符号连接 
S_IFREG   0100000   一般文件 
S_IFBLK   0060000   区块装置 
S_IFDIR   0040000   目录 
S_IFCHR   0020000   字符装置 
S_IFIFO   0010000   先进先出 
S_ISUID   04000   文件的(set   user-id  on   execution)位 
S_ISGID   02000   文件的(set   group-id  on   execution)位 
S_ISVTX   01000   文件的sticky位 
S_IRUSR(S_IREAD)   00400   文件所有者具可读取权限 
S_IWUSR(S_IWRITE)00200   文件所有者具可写入权限 
S_IXUSR(S_IEXEC)   00100   文件所有者具可执行权限 
S_IRGRP   00040   用户组具可读取权限 
S_IWGRP   00020   用户组具可写入权限 
S_IXGRP   00010   用户组具可执行权限 
S_IROTH   00004   其他用户具可读取权限 
S_IWOTH   00002   其他用户具可写入权限 
S_IXOTH   00001   其他用户具可执行权限 
上述的文件类型在POSIX   中定义了检查这些类型的宏定义 
S_ISLNK   (st_mode)   判断是否为符号连接 
S_ISREG   (st_mode)   是否为一般文件 
S_ISDIR   (st_mode)是否为目录 
S_ISCHR   (st_mode)是否为字符装置文件 
S_ISBLK   (s3e)   是否为先进先出 
S_ISSOCK   (st_mode)   是否为socket 
若一目录具有sticky   位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或root来删除或改名。 
  
返回值     执行成功则返回0,失败返回-1,错误代码存于errno 
  
错误代码     ENOENT   参数file_name指定的文件不存在 
ENOTDIR   路径中的目录存在但却非真正的目录 
ELOOP   欲打开的文件有过多符号连接问题,上限为16符号连接 
EFAULT   参数buf为无效指针,指向无法存在的内存空间 
EACCESS   存取文件时被拒绝 
ENOMEM   核心内存不足 
ENAMETOOLONG   参数file_name的路径名称太长 
  
范例     #include  
#include  
mian() 

struct   stat   buf; 
stat   (“/etc/passwd”,&buf); 
printf(“/etc/passwd   file   size   =   %d  /n”,buf.st_size); 

  
执行     /etc/passwd   file   size   =  705 

PS:晚上的德天肥牛吃的我拉肚子怎么说……哭!


你可能感兴趣的:(C/C++)