信安综合实习报告.docx
- 文档编号:14769527
- 上传时间:2023-06-27
- 格式:DOCX
- 页数:26
- 大小:269.02KB
信安综合实习报告.docx
《信安综合实习报告.docx》由会员分享,可在线阅读,更多相关《信安综合实习报告.docx(26页珍藏版)》请在冰点文库上搜索。
信安综合实习报告
Companynumber:
【WTUT-WT88Y-W8BBGB-BWYTT-19998】
信安综合实习报告
PE病毒实验
一实验目的
(1)掌握PE病毒的传播原理。
(2)掌握MASM编译工具的使用。
(3)掌握Ollydbg调试工具的使用。
二实验准备
(1)Windows桌面系统。
(2)MASM32。
(3)Ollydbg调试工具。
(4)Stup_PE等PE文件修改工具。
三预备知识
本节主要介绍PE病毒的基本原理。
本节中的例子均属于概念病毒(概念病毒主要是具
有感染能力的病毒,可能有的病毒具有自动能力,但一般没有破坏性)。
一个Win32PE病毒基本上需要具有以下几个功能,或者说需要解决如下几个问题。
病毒的重定位
call指令一般用来调用一个子程序或用来进行转跳,当这个语句执行的时候,它会先将返回地址(即紧接着call语句之后的那条语句在内存中的真正地址)压入堆栈,然后将IP置为call语句所指向的地址。
当子程序碰到ret命令后,就会将堆栈顶端的地址弹出来,并将该地址存放在IP中,这样,主程序就得以继续执行。
以下代码通常用于重定位:
calldelta;这条语句执行之后,堆栈顶端为delta在内存中的真正地址
delta:
popebp;这条语句将delta在内存中的真正地址存放在ebp寄存器中
leaeax,[ebp+(offsetvar1-offsetdelta)];这时eax中存放着var1在内存中的真实地址
当pop语句执行完毕之后,ebp中存放病毒程序中标号delta处在内存中的真正地址。
如果病毒程序中有一个变量var1,那么该变量在内存中的实际地址应该是ebp+(offsetvar1-offsetdelta),即“参考量delta在内存中的地址+其它变量与参考量之间的距离=其它变量在内存中的真正地址”。
有时候我们也采用(ebp-offsetdelta)+offsetvar1的形式进行变量var1的重定位。
当然还有其它重定位的方法,但是它们的原理基本上都是一样的。
获取API函数地址
如何获取API函数地址一直是病毒技术中的一个非常重要的话题。
要获得API函数地址,我们首先需要获得Kernel32的基地址。
下面介绍几种获得Kernel32基地址的方法:
(1)利用程序的返回地址,在其附近搜索KERNEL32模块基地址。
系统打开一个可执行文件时,它会调用中的CreateProcess函数,CreateProcess函数在完成应用程序装载后,会先将返回地址压入到堆栈顶端,然后转向执行刚才装载的应用程序。
当该应用程序结束后,会将返回地址弹出放到EIP中,继续执行。
而这个返回地址正处于的地址空间之中。
这样,利用PE文件格式的相关特征(如03CH偏移处内容存放着“PE”标志的内存地址等),在此地址的基础上往低地址方向逐渐搜索,必然可以找到模块的首地址。
不过这种暴力搜索方法比较费时,并且可能会碰到一些异常情况。
(2)通过SEH链获得KERNEL32模块内地址遍历SEH链,在链中查找prev成员等于0xFFFFFFFF的EXCEPTION_REGISTER结构,该结构中handler值指向系统异常处理例程,它总是位于KERNEL32模块中!
根据这一特性,然后配合类似
(1)的向前搜索方法就可以查找在内存中的基地址。
(3)通过PEB相关数据结构获取。
fs:
[0]指向TEB结构,首先从fs:
[30h]获得PEB地址,然后通过PEB[0x0c]获得PEB_LDR_DATA数据结构地址,然后通过从PEB_LDR_DATA[0x1c]获取地址,最后在Flink[0x08]中得到模块的基地址。
这种方法比较通用,适用于2K/XP/2003。
在Exploit的编写中,也通常采用这种方式。
(4)对相应操作系统分别给出固定的KERNEL32模块的基地址,对于不同的Windows操作系统来说,KERNEL32模块的地址是固定的,甚至一些API函数的大致位置都是固定的。
譬如,Windows98为BFF70000,Windows2000为77E80000,WindowsXP为77E60000。
病毒在先对目标操作系统进行大致判断之后,可以直接使用相关KERNEL32模块的基地址。
在得到了Kernel32的模块地址以后,我们就可以在该模块中搜索我们所需要的API地址。
对于给定的API,搜索其地址可以直接通过的引出表信息搜索,同样我们也可以先搜索出GetProcAddress和LoadLibrary两个API函数的地址,然后利用这两个API函数得到我们所需要的API函数地址。
关于各个关键项的具体含义我们在课本PE文件格式一节中详细描述过,这里不再重复。
解决了以上问题之后,我们就知道如何从引出表结构查找我们需要函数的地址了。
下面给出已知API函数的函数名搜索API函数地址的过程:
①定位到PE文件头。
②从PE文件头中的可选文件头中取出数据目录表的第一个数据目录,得到导出表的地址。
③从导出表的NumberOfNames字段得到以命名函数的总数,并以这个数字做微循环的次数来构造一个循环。
④从AddressOfNames字段指向的函数名称地址表的第一项开始,在循环中将每一项定义的函数名与要查找的函数名比较,如果没有任何一个函数名符合,说明文件中没有指定名称的函数。
⑤如果某一项定义的函数名与要查找的函数名符合,那么记住这个函数名在字符串地址表中的索引值(如x),然后在AddressOfNameOrdinals指向的数组中以同样的索引值x去找数组项中的值,假如该值为m。
⑥以m值作为索引值,在AddressOfFunctions字段指向的函数入口地址表中获取的RVA就是函数的入口地址,当函数被装入内存后,这个RVA值加上模块实际装入的基址(ImageBase),就得到了函数真正的入口地址。
对病毒来说,通常是通过API函数名称来查找API函数地址。
找到某一函数名称之后,可以通过与目标函数名直接进行字符串比较来判断是否找到所需要的函数;也可以事先对API函数名称进行相关计算得到一个特征值,以后每次找到某一函数名称之后,对该函数名称用同样的算法计算特征值,如果两值相等,则说明找到需要的目标函数。
后者相对而言节省了空间,但可能耗费更多时间。
文件搜索
搜索目标文件是病毒技术中一个非常重要的功能。
在Win32汇编中,通常用到了几个关键的API函数和一个WIN32_FIND_DATA结构:
FindFirstFile:
该函数根据文件名查找文件,如果该函数执行成功,其返回一个搜索句柄。
如果出错,返回一个INVALID_HANDLE_VALUE常数,一旦不再需要,应该用FindClose函数关闭这个句柄。
FindNextFile:
该函数根据调用FindFirstFile函数时指定的一个文件名查找下一个文件,返回值非零表示成功,零表示失败。
如不再有与指定条件相符的文件,会将GetLastError设置成ERROR_NO_MORE_FILES。
FindClose:
该函数用来关闭由FindFirstFile函数创建的一个搜索句柄,返回值非零表示成功,零表示失败。
会设置GetLastError。
WIN32_FIND_DATA结构中存放着找到的文件的详细信息,具体结构如下所示:
WIN32_FIND_DATASTRUCT
dwFileAttributesDWORD
③该目录搜索完毕是则返回,否则继续
④找到文件还是目录是目录则调用自身函数FindFile,否则继续
⑤是文件,如符合感染条件,则调用感染模块,否则继续
⑥搜索下一个文件(FindNextFile),转到C继续FindFileEndp
内存映射文件
内存映射文件提供了一组独立的函数,这组内存映射文件函数将磁盘上的文件的全部或者部分映射到进程虚拟地址空间的某个位置,以后对文件内容的访问就如同在该地址区域内直接对内存访问一样简单。
这样,对文件中数据的操作便是直接对内存进行操作,大大地提高了访问的速度,这对于计算机病毒来说,对减少资源占有是非常重要的。
在计算机病毒中,通常采用如下几个步骤:
①调用CreateFile函数打开想要映射的HOST程序,返回文件句柄hFile。
②调用CreateFileMapping函数生成一个建立基于HOST文件句柄hFile的内存映射对象,返回内存映射对象句柄hMap。
③调用MapViewOfFile函数将整个文件(一般还要加上病毒体的大小)映射到内存中。
得到指向映射到内存的第一个字节的指针(pMem)。
④用刚才得到的指针pMem对整个HOST文件进行操作,对HOST程序进行病毒感染。
⑤调用UnmapViewFile函数解除文件映射,传入参数是pMem。
⑥调用CloseHandle来关闭内存映射文件,传入参数是hMap。
⑦调用CloseHandle来关闭HOST文件,传入参数是hFile。
病毒如何通过添加新节感染其他文件
PE病毒感染其他文件的方法之一是在文件中添加一个新节,然后往该新节中添加病毒代码和病毒执行后的返回Host程序的代码,并修改文件头中代码开始执行位置(AddressOfEntryPoint)指向新添加的病毒节的代码入口,以便程序运行后先执行病毒代码。
下面我们具体分析一下感染文件步骤(这种方法将会在后面的例子中有具体代码介绍)。
感染文件的基本步骤
(1)判断目标文件开始的两个字节是否为“MZ”。
(2)判断PE文件标记“PE”。
(3)判断感染标记,如果已被感染过则跳出继续执行HOST程序,否则继续。
(4)获得Directory(数据目录)的个数,(每个数据目录信息占8个字节)。
(5)得到节表起始位置。
(Directory的偏移地址+数据目录占用的字节数=节表起始位置)
(6)得到目前最后节表的末尾偏移(紧接其后用于写入一个新的病毒节)节表起始位置+节的个数*(每个节表占用的字节数28H)=目前最后节表的末尾偏移。
(7)写入节表和修改PE文件其他相关首部
①写入节名(8字节)。
②写入节的实际字节数(4字节)。
③写入新节在内存中的开始偏移地址(4字节),同时可以计算出病毒入口位置。
上节在内存中的开始偏移地址+(上节大小/节对齐+1)×节对齐=本节在内存中的开始偏移地址。
④写入本节(即病毒节)在文件中对齐后的大小。
⑤写入本节在文件中的开始位置。
上节在文件中的开始位置+上节对齐后的大小=本节(即病毒)在文件中的开始位置。
⑥修改映像文件头中的节表数目。
⑦修改AddressOfEntryPoint(即程序入口点指向病毒入口位置),同时保存旧的AddressOfEntryPoint,以便返回HOST继续执行。
⑧更新SizeOfImage(内存中整个PE映像尺寸=原SizeOfImage+病毒节经过内存节对齐后的大小)。
⑨写入感染标记(后面例子中是放在PE头中)。
(8)写入病毒代码到新添加的节中。
ECX=病毒长度
ESI=病毒代码位置(并不一定等于病毒执行代码开始位置)
EDI=病毒节写入位置(后面例子是在内存映射文件中的相应位置)
(9)将当前文件位置设为文件末尾。
文件操作相关API函数
(1)CreateFile该函数可打开和创建文件、管道、邮槽、通信服务、设备以及控制台,如执行成功,则返回值为文件句柄。
返回值INVALID_HANDLE_VALUE则表示出错。
即使函数成功,但若文件存在,且指定了CREATE_ALWAYS或OPEN_ALWAYS,GetLastError也会设为ERROR_ALREADY_EXISTS。
(2)SetFilePointer该函数在一个文件中设置当前的读写位置。
(3)ReadFile该函数用来从文件中读取数据。
(4)WriteFile该函数用来将数据写入文件。
(5)SetEndOfFile该函数针对一个打开的文件,将当前文件位置设为文件末尾。
(6)GetFileSize该函数用来返回指定文件的长度。
。
(7)FlushFileBuffers该函数将指定的文件句柄对应文件的缓冲区的所有内容写入到文件之中,并刷新内部文件缓冲区。
病毒如何返回到Host程序
为了提高自己的生存能力,病毒是不应该破坏HOST程序的,既然如此,病毒应该在病毒执行完毕后,立刻将控制权交给HOST程序,病毒如何做到这一点呢
返回HOST程序相对来说比较简单,病毒在修改被感染文件代码开始执行位置(AddressOfEntryPoint)时,会保存原来的值,这样,病毒在执行完病毒代码之后用一个跳转语句跳到这段代码处继续执行即可。
四实验内容
在实验之前,必须关闭防病毒软件。
否则实验可能无法正常完成。
(1)使用RadASM或者Masm32自带的QEDITOR编辑和编译程序源代码。
下载Masm32V8,并将其安装到C盘根目录中(C:
\masm32),进入C:
\masm32,打开编写源代码,并保存为.asm文件(例子中有4个asm文件,这4个asm文件应该在同一个目录下,其中为主文件)。
也可以选择其他编辑软件编写好汇编代码之后,然后用打开该asm文件。
打开,选择QEDITOR的菜单栏进行masm和link将会得到最终的可执行程序()。
发现编译通不过:
查看源代码,找出错误并修改:
然后重新编译,完成后则可生成的可执行病毒程序:
病毒程序由于需要对自身代码节进行修改,但默认情况下代码节是不可写的,因此要将代码节的属性进行修改。
这里给出利用PE修改工具直接修改可执行程序的方法。
编译完毕之后,利用PE修改工具对目标文件代码节的属性进行修改。
我们可以通过Stud_PE等程序来修改C:
\masm32\程序的.text节的属性为可写(选中“MEM_WRITE”,然后保存即可)。
利用Sutd_PE对PE可执行程序的节属性进行修改
(2)编译或者任意选择一个简单的PE可执行程序(例如功能为“弹出一个窗口”的程序或随便选择一个小游戏等),作为被感染的目标程序,将该程序放在病毒程序指定的目录,并以指定的文件名命令。
在这里的感染中,被感染程序命名为,并且和病毒感染程序在同一个目录之中。
(3)执行编译出来的病毒程序。
(4)如果顺利,则现在的程序应该已被感染,它将首先执行病毒程序的代码,执行完毕之后将继续执行原有程序的功能代码。
(5)打开Ollydbg(或Ollydbg,SoftIce,W32dasm)对编译出来的可执行文件进行调试。
如果感染程序功能不正常,则通过Ollydbg来寻找原因,并对源程序进行修正。
(6)跟踪API函数的获取以及添加新节的过程。
(7)利用UltraEdit或者其他PE编辑工具恢复被感染的程序。
观察病毒文件代码,打开被感染文件:
可以看到,文件中插入了病毒的那段代码。
对其进行修改即可还原文件。
完全脆弱图像水印
一实验目的
了解什么是脆弱性水印和半脆弱性水印,掌握实现半脆弱水印和脆弱水印的原理,设计并实现一种完全脆弱水印的实验方法。
二实验环境
(1)WindowsXP操作系统
(2)科学计算软件
(3)图像文件
三原理简介
在保证多媒体信息一定感知质量的前提下,将数字、序列号、文字、图像标志等做为水印嵌入到多媒体数据中,当多媒体内容受到怀疑时,可将水印提取出来用于媒体内容的真假识别,并指出篡改位置,甚至攻击类型等。
这种水印称为脆弱水印,脆弱水印分为完全脆弱水印和半脆弱水印。
当原始载体内容发生改变时,被嵌入的水印信息就遭到破坏,因此图像的接收方就不能完整地提取水印信息。
从而可以鉴定原始数据是否被篡改。
完全脆弱水印主要用于完整性保护,图像不能发生任何修改,图像如果发生一个比特的修改都会影响水印信息的提取。
而半脆弱水印对一般图像处理(如:
滤波、加噪声、压缩等)有较强的免疫能力(鲁棒性),但是能检测到对图像的恶意篡改,一般用于内容保护。
完全脆弱水印系统要求图像的任何细微的变动都会做出拒绝判决。
完全脆弱水印一般是从空域LSB水印算法演变过来,其中最有代表性的是校验和算法、公钥认证水印算法、查找表水印算法。
校验和算法原理如下:
首先计算每个像素字节最高7位的checksum值,checksum值定义为一系列相同长度的二进制的模2和。
此长度为8个连续像素中的最高7位的联合长度,共56位。
在checksum值计算过程中,整幅图像中的每个像素都参与计算,但每个都只计算一次,最后结果为56位的数据。
随后在图像中随机选取56个像素,将每个像素的最低位变为与上述checksum比特位相同,以此存储checksum值,从而完成水印的嵌入。
图像认证时,只需要将被检测图像的CHECKSUM值与提取的水印做比较,便可以知道图像是否衩篡改。
在这个算法中,随机选择的存放Checksum值的图像位置以及Checksum值本身构成了水印信息。
在提取水印时,只需计算图像的Checksum值并与水印信息中的Checksum值进行比较,便可知水印是否因遭受篡改而被破坏。
四实验步骤
水印嵌入
根据以上所说的checksum算法,我在环境下面实现了该程序,由于win7的兼容性问题,程序只能是windows经典模式下面可以运行:
img=imread('C:
\DocumentsandSettings\Administrator\桌面\');
x=rgb2gray(img);
[wide,high]=size(x);
temp=[uint8(0)uint8(0)uint8(0)uint8(0)uint8(0)uint8(0)uint8(0)uint8(0)];
forii=1:
wide
forjj=1:
high
ifmod((wide*(ii-1)+jj),8)==0
temp
(1)=bitxor(temp
(1),x(ii,jj));
elseifmod((wide*(ii-1)+jj),8)==1
temp
(2)=bitxor(temp
(2),x(ii,jj));
elseifmod((wide*(ii-1)+jj),8)==2
temp(3)=bitxor(temp(3),x(ii,jj));
elseifmod((wide*(ii-1)+jj),8)==3
temp(4)=bitxor(temp(4),x(ii,jj));
elseifmod((wide*(ii-1)+jj),8)==4
temp(5)=bitxor(temp(5),x(ii,jj));
elseifmod((wide*(ii-1)+jj),8)==5
temp(6)=bitxor(temp(6),x(ii,jj));
elseifmod((wide*(ii-1)+jj),8)==6
temp(7)=bitxor(temp(7),x(ii,jj));
elseifmod((wide*(ii-1)+jj),8)==7
temp(8)=bitxor(temp(8),x(ii,jj));
end
end
end
tpwide=1;
tphigh=1;
counter=1;
tp=0;
forii=1:
8
forkk=1:
7
ifkk==1
tp=bitand(temp(ii),uint8(128));
iftp==0
ifmod(x(counter),2)==1
x(counter)=bitand(x(counter),uint8(254));
end
else
ifmod(x(counter),2)==0
x(counter)=bitor(x(counter),uint8
(1));
end
end
elseifkk==2
tp=bitand(temp(ii),uint8(64));
iftp==0
ifmod(x(counter),2)==1
x(counter)=bitand(x(counter),uint8(254));
end
else
ifmod(x(counter),2)==0
x(counter)=bitor(x(counter),uint8
(1));
end
end
elseifkk==3
tp=bitand(temp(ii),uint8(32));
iftp==0
ifmod(x(counter),2)==1
x(counter)=bitand(x(counter),uint8(254));
end
else
ifmod(x(counter),2)==0
x(counter)=bitor(x(counter),uint8
(1));
end
end
elseifkk==4
tp=bitand(temp(ii),uint8(16));
iftp==0
ifmod(x(counter),2)==1
x(counter)=bitand(x(counter),uint8(254));
end
else
ifmod(x(counter),2)==0
x(counter)=bitor(x(counter),uint8
(1));
end
end
elseifkk==5
tp=bitand(temp(ii),uint8(8));
iftp==0
ifmod(x(counter),2)==1
x(counter)=bitand(x(counter),uint8(254));
end
else
ifmod(x(counter),2)==0
x(counter)=bitor(x(counter),uint8
(1));
end
end
elseifkk==6
tp=bitand(temp(ii),uint8(4));
iftp==0
ifmod(x(counter),2)==1
x(counter)=bitand(x(counter),uint8(254));
end
else
ifmod(x(counter),2)==0
x(counter)=bitor(x(counter),uint8
(1));
end
end
elseifkk==7
tp=bitand(temp(ii),uint8
(2));
iftp==0
ifmod(x(counter),2)==1
x(counter)=bitand(x(counter),uint8(254));
end
else
ifmod(x(counter),2)==0
x(counter)=bitor(x(counter),uint8
(1));
end
end
end
counter=counter+1;
end%for
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 综合 实习 报告