|
楼主 |
发表于 2020-2-19 23:53:19
|
显示全部楼层
2020年2月19日:
今天老师讲了shellcode的相关知识,然后我发现自己在之前写shellcode时,还存在一些问题,今天就来补充一下!
之前提取shellcode都是直接利用C语言代码进行异或得到shellcode,或者是在反汇编里找到汇编对应的机器码提取shellcode,接下来先来看两种提取shellcode的方式:
1.利用kali里面的msf-nasm_shell
然后把这些全部复制到一个文本里,把汇编对应的二进制码提取出来,然后大写字母换成小写并给每两个字符前面加上\x,就得到了shellcode
2.通过汇编程序,如下,在进行这个编码的过程中,因为我们把原始shellcode地址给了eax,则eax对应内存里的值就会变化,在执行过这段程序时,原始shellcode会一次次编码,直到最后一个90也发生改变,则我们就可以把右边改变的数提取出来,加上\x,就得到了编码后的shellcode,也就是edcstr。
- #include "stdio.h"
- char shellcode[]="\x8b\x04\x24\x83\xc0\x17\x33\xc9\x8a\x1c\x08\x80\xf3\x13\x88\x1c\x08\x41\x80\xfb\x90\x75\xf1\xab\x45\x13\x13\x13\xa8\x27\x13\x13\x13\x10\xd0\x83\x90\x90\x90\x90";
- int main(int argc, char* argv[])
- {
- char oristr[]="\xB8\x56\x00\x00\x00\xBB\x34\x00\x00\x00\x03\xC3\x90";
- char dscstr[]="\xAB\x45\x13\x13\x13\xA8\x27\x13\x13\x13\x10\xD0\x83";
- __asm
- {
- // lea eax, shellcode
- // push eax
- // mov eax,[esp] // 对应的机器码是\x8b\x04\x24,这里是对编码后的shellcode基址的一个定位,我们之前的解密子就是少了这一部分。
- add eax,17h // 对应的机器码是\x83\xc0\x17\,17h也就是23,指的整个shellcode的长度,这里通过加上偏移地址,就可以跳过解密子部分,准确的到encstr的位置。
- lea eax,shellcode
- push eax //这里进行两次push eax,是为了让返回的地址刚好指向shellcode的首地址。下面有张图会进行清楚的分析。
- push eax
- ret
- // lea eax,str
- // push eax
- // ret
- /*
- lea eax,oristr // 可以通过这部分代码将oristr进行编码
- xor ecx,ecx
- ee:
- mov bl, [eax+ecx]
- xor bl,0x13
- mov [eax+ecx],bl
- inc ecx
- cmp bl,0x90
- jne ee */
- /*mov eax,56h
- mov ebx,34h
- add eax,ebx //这一部分的机器码就是oristr,可以通过方法一提取出来。
- nop
- */
- }
- printf("%s\n",shellcode);
- return 0;
- }
复制代码 就是这张图,当执行完ret指令后,esp的值为0012ff10,并且此时的0012ff0c的值也就是第一个进栈的shellcode已经弹出去了,所以需要两次push eax,才可以跳回到shellcode的首地址
当我们调试那部分shellcode的时候,会发现它一直跳动执行,然后会见将最终要执行的shellcode显示出来。
当然这些代码运行是会报错的,因为我们对shellcode之后未作处理。
接下来进入对C语言代码的汇编:
第一个C语言代码:
- #include<stdio.h>
- void main()
- {
- int a,b,total;
- a=10;
- b=3;
- total=a*b;
- printf("total=&d\n",total);
- }
复制代码 这是一个比较简单的实现乘法的程序
1.先看main函数的反汇编:
- 00401010 push ebp //把原来的ebp保护起来,因为我们进行计算或是操作的时候要在一个新栈里进行,不能影响之前的栈的结构
- 00401011 mov ebp,esp
- 00401013 sub esp,4Ch //抬高栈顶,给新栈扩大空间
- 00401016 push ebx
- 00401017 push esi
- 00401018 push edi
- 00401019 lea edi,[ebp-4Ch]
- 0040101C mov ecx,13h
- 00401021 mov eax,0CCCCCCCCh //eax清c
- 00401026 rep stos dword ptr [edi] //重复串操作
- ……
- ……
- 00401051 pop edi
- 00401052 pop esi
- 00401053 pop ebx //把push进来的东西,按照先进后出的顺序pop出去
- 00401054 add esp,4Ch
- 00401057 cmp ebp,esp
- 00401059 call __chkesp (004011b0)
- 0040105E mov esp,ebp
- 00401060 pop ebp //恢复到之前的ebp
- 00401061 ret
复制代码 2.中间的计算的汇编
- 4: int a,b,total;
- 5: a=10;
- 00401028 mov dword ptr [ebp-4],0Ah
- 6: b=3;
- 0040102F mov dword ptr [ebp-8],3
- 7: total=a*b;
- 00401036 mov eax,dword ptr [ebp-4]
- 00401039 imul eax,dword ptr [ebp-8]
- 0040103D mov dword ptr [ebp-0Ch],eax
- 8: printf("total=&d\n",total);
- 00401040 mov ecx,dword ptr [ebp-0Ch]
- 00401043 push ecx
- 00401044 push offset string "total=&d\n" (00427008)
- 00401049 call printf (00401080)
- 0040104E add esp,8
复制代码 3,下面是我写的汇编代码:
- #include<stdio.h>
- void main()
- {
- int a=3,b=10,c;
- char *str="total=%d\n";
- _asm{
- mov eax,a
- imul eax,b
- mov ecx,eax
- push ecx
- push str
- call printf
- add esp,8
- }
- }
复制代码
运行成功!
下面这个也是可以的,就是不用把eax值赋给ecx
今天试的时候还犯了一个错误如下,我们写的是C语言嵌入式汇编,所以写main函数里面的汇编就可以了,我今天真的是画蛇添足,记录一下以后就不会在犯了!!!
第二个c语言代码
- #include<stdio.h>
- void main{
- int a,b,c,d;
- unsigned u;
- a=12;b=-24;u=10;
- c=a+u; d=b+u;
- printf("a+u=%d,b+u=%d",c,d);
- }
复制代码
我写的汇编代码:
- #include<stdio.h>
- void main()
- {
-
- char *str="a+u=%d,b+u=%d\n";
- _asm{
- mov eax,0Ch
- add eax,0Ah
- mov ebx,0FFFFFFE8h
- add ebx,0Ah
- push ebx
- push eax
- push str
- call printf
- add esp,12
- };
- }
复制代码
运行成功!
这里主要注意两点:
1.栈是先进后出的,所以要先让ebx压栈,然后eax在进栈,这样才能使eax比ebx先出栈。
2.如何把负数转换位对应的16进制,我在网上找了一个比较明了的教程:https://blog.csdn.net/xiaochunyong/article/details/7616625
太难了,刚刚不小心把写的东西关掉了,再打开恢复数据已经所剩无几了,又重新写了一遍!先写这么多吧,还有没写的明天再做记录.
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|