用了怎么长时间的命令行方式,咱们发现了几个问题c++
1.没有代码提醒功能编程
2.编写代码很慢,记不住各类声明windows
那么如今有大神,已经帮咱们作了一个IDE环境,就是RadAsm,首先简单介绍一下界面安全
(对于这个IDE(最新版是3.0)我已经打包好了,有中文版本,和英文版本)app
咱们须要配置一下环境函数
打开后会弹出工具
首先这里咱们注意下面的几个选项字体
1.编译选项 Assemble : 这个是默认的便可,若是你是编译32位程序,那么咱们就用 /c /coff 便可,后面几个默认spa
2.链接选项 link: 通常是默认的,他是默认生成windows的程序,若是咱们有控制台的程序,那么咱们能够手工去编译,命令行
也能够经过它的项目,新建项目的时候选择指定的
3.扩展的调试器 External debugger: 这个则配置咱们od所在的路径便可,3.0版本已经能够支持选择调试器了,之前的版本则是你指定文件夹,默认的调试器是Ollydbg.exe,因此咱们名字还要改成这个才能够
4.library: 库的路径,有时候你编写汇编程序,会使用lib库,也会使用inc文件,那么能够把咱们昨天的MASM32的库路径放到这里,也能够用高版本的,好比vc++6.0的,或者vs系列的都是能够的
注意:
上面配置的编译选项,以及链接选项,咱们都是安装的MASM32的,也就是昨天提供的工具,咱们把它的路径设置为环境变量,这样就能够用编译的指令了,例如 /c /coff ....,若是你没有安装,或者没有配置环境变量,那么计算机就会找不到编译器,进而你的/c /coff就是错误的,因此咱们还须要设置环境变量
上面咱们已经设置了调试器.下面咱们设置环境变量
点击 Option -> Environment
弹出界面
能够看到有三个路径:
path include lib
分别加上咱们的MASM 目录便可.
例如Path
你的Masm路径\bin
include 路径
lib 路径同上
建议使用Radasm 3.0 虽然是英文版.都是单词都很简单. 之前的我用了下有Bug. 例如程序运行以后不关闭.
关于RadAsm的字体,以及中文乱码,网上有不少解决方法,这里我只对当前最新版本的RadAsm3.0作一个讲解
选择代码编辑
从上往下看
1.第一个红框,选择的是Masm的背景颜色,以及主题,这个能够自由设置很少作讲解
2.第二个红框,Tab Size 4,这里是编写汇编代码的时候Tab制表符,的距离,咱们能够设置为2个
3.第三个红框,分别有个Code(代码按钮),和Line Number(行号的按钮)
这里则是设置代码字体的大小,还有行号显示的大小
首先中文乱码问题,打开code(代码编辑)
在这里设置代码字体的时候,必定注意要把下面的语言换成 ""中文 GB2312 " 而不是默西欧语言
选择了便可解决中文乱码的问题
1.打开 Project(项目) - > new Project(新建项目)
2.选择项目编译的语言,(这里我使用masm),选择项目生成的路径
默认便可
编写咱们的第一段代码,而且调试输出
1,编译链接一块儿执行
,
快捷键是Ctrl + F5 编译运行
1.编译快捷键 是 F5 会生成obj中间文件
3.连接快捷键是 Ctrl + Alt + F5 将obj文件生成exe
4. 编译并链接 shift + alt + f5 直接将编译链接在一块儿了.
4.调试快捷键是 Ctrl + D 它会默认打开咱们的OD调试器,而且附加咱们的程序,咱们试一下
打开了咱们的OD调试器,而且开始调试了
打开了咱们的OD调试器,而且开始调试了
其他功能,本身尝试,若是不会配置,也能够在下方评论,那么我看到则会帮你解决,而后若是有好心人看到也会帮你一把
在讲解汇编程序注入代码的时候,咱们须要先明白,远程线程注入的原理,我会写一个远程线程开发的例子,这样有助于咱们理解汇编注入
咱们总共须要几步
/*1.查找窗口,获取窗口句柄*/ /*2.根据窗口句柄,得到进程的PID*/ /*3.根据进程的PID,得到进程的句柄*/ /*4.根据进程的句柄,给进程申请额外内存空间*/ /*5.调用WriteProcessMemory,给进程写入DLL的路径*/ /*6.建立远程线程,执行咱们的代码*/ /*7.调用退出代码,释放远程线程的dll*/
每一步单独讲解
咱们新建一个MFC 对话框程序,添加一个按钮,这个按钮专门响应注入的实现
第一步: 查找窗口,得到窗口句柄(采用WindowsAPI FindWindow,传入窗口名称,而后找到则返回对应的窗口句柄)
HWND hWnd = FindWindow("","计算器"); if(NULL == hWnd) { return; //失败则返回 }
第二步: 根据窗口句柄,查找进程PID (调用 GetWindowThreadProcessId API,传入窗口句柄,而后经过第二个参数把进程的PID给咱们的参数)
/*2.根据窗口句柄,得到进程的PID*/ DWORD DwPid = 0; GetWindowThreadProcessId(hWnd,&DwPid); //这个函数会返回线程的ID,可是咱们不关心,因此没有加返回值
第三步: 根据进程PID,返回进程的句柄(OpenProcess,参数一,权限 参数二,句柄是否继承,参数三,进程的pid)
/*3.根据进程的PID,得到进程的句柄*/ HANDLE hProHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,DwPid); //参数一,选择全部权限,参数二,不继承给false,参数三,给咱们上面得到的pid的值 if(NULL == hProHandle) { return; }
第四步: 给远程进程申请空间,而且返回空间的首地址(调用的API 是VirtualAllocEx)
/*4.根据进程的句柄,给进程申请额外内存空间*/ LPVOID lpAddr = VirtualAllocEx(hProHandle,NULL,0x1000,MEM_COMMIT,PAGE_EXECUTE_READWRITE); if(NULL == lpAddr) { return ; }
VirtualAllocEx说明:
第一个参数: 进程的句柄
第二个参数: 指定位置分配内存,给NULL为默认帮咱们找块地方申请内存(不过这个地址会返回,因此不关心)
第三个参数: 内存分配多大,咱们给了4096个字节大小,也就是一个分页(1000H)
第四个参数: 是否当即申请,仍是保留这块内存,只能给咱们用,可是还没申请,咱们选择当即申请
第五个参数: 权限,你申请的这块内存是什么内存,只能读,仍是只能写,仍是只能执行,咱们选择所有,可读可写可执行
第五步:调用WriteProcessMemory将咱们的Dll路径,写入到远程进程中
/*5.调用WriteProcessMemory,给进程写入DLL的路径*/ char szBuf[MAX_PATH] = {NULL}; GetCurrentDirectory(sizeof(szBuf),szBuf); //这三行代码主要是拼接咱们的DLL,DLL是咱们本身写的 strcat(szBuf,"StaticDll.dll"); //DLL这里就不写了,用个人吧,我会发上去的
BOOL bRet = WriteProcessMemory(hProHandle,lpAddr,szBuf,strlen(szBuf)+1,NULL); if(!bRet) { return; }
WriteProcessMemory讲解:
第一个参数: 进程的句柄,能够用咱们上面的OpenProcess返回的
第二个参数: 你要写入的地址,地址使咱们VirtualAllocEx申请以后返回的(就是你要往哪一个地址写内容)
第三个参数: 你写入的内容是什么,写入的内容使咱们的Dll路径,上面已经拼接好了
第四个参数: 你写入的内容的大小是多大,这里咱们用strlen求出来了
第五个参数: 实际写入的个数,咱们不关心,若是你想知道,则定义一个变量,而后 取地址传入便可,由于是个指针
第六步: 远程进程开辟线程,调用LoadLibrary,加载咱们的dll,而大家知道,当dll被加载的时候,会有信息
因此咱们在咱们的dll里面写入咱们本身的代码,好比这个dll被加载的时候,咱们执行咱们的代码,
这里个人代码就是找到计算器,而后给它加个菜单,而且响应消息
HANDLE hThreadHandle = CreateRemoteThread(hProHandle, NULL, 0, (LPTHREAD_START_ROUTINE)LoadLibrary, lpAddr, 0, NULL);
核心代码就在这里,咱们必需要知道,咱们如今加载咱们的DLL,而咱们的DLL被加载的时候,就要执行本身的代码
因此这个时候就能够执行代码了
CreateRemoteThread讲解:
第一个参数: 进程的句柄(你要往哪一个进程开辟线程)
第二个参数: 安全属性,句柄能否继承,不须要给NULL
第三个参数: 栈的大小,给0则默认
第四个参数: 函数执行,咱们要开辟线程,开辟的线程叫作loadLibrary
第五个参数: 开辟线程传入的参数,咱们知道,线程只有一个参数,而如今正好load也是一个参数,因此加载的参数就是咱们的
写入远程进程内存的dll路径,而dll路径一旦启动,则会执行本身的代码(核心,必定掌握)
第六个参数: 建立的标志,默认给0
第七个参数: 线程的ID,不须要知道,给NULL
咱们尝试一下是否能够成功注入计算器,而且加入菜单
已经成功注入了.对于完整的代码,我会放到课堂资料中,可是这几步,必定要亲自手动弄明白
(备注: 我是使用VC++6.0编写代码,是MFC程序,固然你也能够用高版本,参考我这个,是同样的
对于DLL,我也会发,大家能够本身去写本身的DLL,好比一个空DLL会有DLL main,也就是dll的入口点
当第一次加载的时候会来信息什么的,因此能够在里面写代码.dll靠本身,这里只提供思路)
注意,别看博客天天内容不多,其实你想真正掌握,没有2-3个小时就不算掌握,当你真正明白这个知识点了,那才叫掌握,而不是看一遍就走的,自觉得已经会了,千万不要眼高手低
好比上面的远程线程注入,原理是什么,虽然我代码给你了,当你知道原理了,那么代码本身就会写了
原理: 原理就是找到进程,利用VirtualAllocEX给他开辟个空间,利用他的返回值,会返回这个空间的地址
而后再利用WriteProcessMemory给这块空间写入DLL的路径,最后利用远程线程(CreateRemoteThread)
把loadlibrary当作线程回调执行,传入的参数就是远程进程空间咱们写入的DLL路径,
这样至关于当另外一个进程 调用了LoadLibray,而且加载咱们的DLL,而利用DLL被加载会执行的机制,
而后在咱们的DLL中写入被加载时候的代码便可.
(对于为何咱们肯定loadlibary在远程进程中,其实这个是系统的特性,重要你软件一启动,就必然要有dll的支持
而咱们调用的loadlibary就在这些dll中)
首先,前边介绍了RadAsm的IDE环境,那么咱们利用他创建一个Dlg汇编程序
1.首先,新建工程,建立一个窗口程序
(由于对于RadAsm3.0不太熟悉,因此这里不用3.0了,仍是用2.2.2.0)
选择win32 app
选择 dialog app
生成的时候注意ID和窗口名
,对于ID,和IDname,咱们须要本身去定义宏
而后在窗口过程函数相应咱们的消息
注意,对于资源,咱们必须单独编译,快捷键是 shift + F5
Ctrl + F5 编译运行
如今已经能够正常执行了
咱们OD看一下,
Ctrl + D
下断点以后,消息来了,咱们知道了WM_COMMAND消息是0x111,因此就直接调用MessageBox函数了
看汇编代码,咱们会执行上面的那几个步骤
先把变量定义出来
LOCAL @hWnd:HWND ;查找窗口返回窗口句柄 LOCAL @hProcessHandle:HANDLE: ;进程句柄 LOCAL @dwPid:DWORD ;进程的PID LOCAL @lpBuf:PVOID ;远程进程开辟空间的首地址 LOCAL @hThread:HANDLE ;线程的句柄 LOCAL @dwExitCode:DWORD ;退出代码,获取的是远程load的返回值 ;这些变量都是定义在窗口过程函数中
第一步,判断按钮ID,而且查找窗口句柄
;1.解析低位,得到按钮消息,而且查找窗口句柄 invoke FindWindow,NULL, offset g_szWindowName mov @hWnd,eax ;把返回值给@hWnd .if eax == NULL ret .endif
第二步:得到进程的PID
invoke GetWindowThreadProcessId, @hWnd, addr @dwPID
第三步: 得到进程句柄
invoke OpenProcess,PROCESS_ALL_ACCESS, FALSE, @dwPID
mov @hProcess, eax
.if eax == NULL
ret
.endif
第四步:申请内存空间
invoke VirtualAllocEx,@hProcess, NULL, 1000h, MEM_COMMIT, PAGE_EXECUTE_READWRITE mov @lpBuff, eax .if eax == NULL invoke ShowLastError ret .endif
第五步: 直接写入代码,写入(按照之前,是往内存写入DLL路径,这里咱们把代码写进去)
invoke WriteProcessMemory,@hProcess,
@lpBuff,
INJECT_CODE, ;代码的标号
start - INJECT_CODE, ;起始位置-标号等于实际大小
NULL
标号是写在代码区的上面的
一会OD调试一下看看
至于为何写入的代码要ret 4,也就是start上面的那句话,是由于
下面咱们调用CreateRemoteThread的时候,其中一个参数是@lpbuf,咱们是当作函数调用的,因此压入一个返回地址
第六步: 建立远程线程
invoke CreateRemoteThread,@hProcess, NULL, 0, @lpBuf, NULL, 0, NULL mov @hThread, eax .if eax == NULL ret .endif invoke WaitForSingleObject,@hThread, INFINITE 等待结束 invoke GetExitCodeThread, @hThread, addr @dwExitCode 获取loadlibrary的返回值
他的返回值实际上是dll在内存中的实例句柄,因此咱们须要释放掉.(释放本身能够搜一下,暂时先把主要的讲了)
OD分析 明天讲解,今天先熟悉一下代码,内容比较多,消化一下
课堂资料:
连接:http://pan.baidu.com/s/1o7B9f2i 密码:5kcu