给程序加壳

在内存中运行可执行程序,好处是可以给程序加壳,加密源程序,静态反汇编无法获得PE输入节,但是因为运行后仍然是独立的进程,所以没办法防止远程线程注入,挂接API钩子。

   typedef IMAGE_SECTION_HEADER ( * PIMAGE_SECTION_HEADERS)[ 1 ];  
 
 //  计算对齐后的大小   
 unsigned  long  GetAlignedSize(unsigned  long  Origin, unsigned  long  Alignment)  
  {  
     return  (Origin  +  Alignment  -   1 )  /  Alignment  *  Alignment;  
}   
 
 //  计算加载pe并对齐需要占用多少内存  
 //  未直接使用OptionalHeader.SizeOfImage作为结果是因为据说有的编译器生成的exe这个值会填0   
 unsigned  long  CalcTotalImageSize(PIMAGE_DOS_HEADER MzH  
                                 , unsigned  long  FileLen  
                                 , PIMAGE_NT_HEADERS peH  
                                 , PIMAGE_SECTION_HEADERS peSecH)  
  {  
    unsigned  long  res;  
     //  计算pe头的大小   
     res  =  GetAlignedSize( peH -> OptionalHeader.SizeOfHeaders , peH -> OptionalHeader.SectionAlignment);  
 
     //  计算所有节的大小   
      for (  int  i  =   0 ; i  <  peH -> FileHeader.NumberOfSections;  ++ i)  
      {  
         //  超出文件范围   
          if (peSecH[i] -> PointerToRawData  +  peSecH[i] -> SizeOfRawData  >  FileLen) 
          {
             return   0 ;  
        }
         else   if (peSecH[i] -> VirtualAddress) // 计算对齐后某节的大小   
            {  
             if (peSecH[i] -> Misc.VirtualSize)  
              {  
                res  =  GetAlignedSize( peSecH[i] -> VirtualAddress  +  peSecH[i] -> Misc.VirtualSize  
                    , peH -> OptionalHeader.SectionAlignment);  
            }   
             else  
              {  
                res  =  GetAlignedSize( peSecH[i] -> VirtualAddress  +  peSecH[i] -> SizeOfRawData  
                    , peH -> OptionalHeader.SectionAlignment);  
            }   
        }   
         else   if ( peSecH[i] -> Misc.VirtualSize  <  peSecH[i] -> SizeOfRawData )  
          {  
            res  +=  GetAlignedSize( peSecH[i] -> SizeOfRawData  
                , peH -> OptionalHeader.SectionAlignment);  
        }   
         else  
          {  
            res  +=  GetAlignedSize( peSecH[i] -> Misc.VirtualSize  
                , peH -> OptionalHeader.SectionAlignment);  
        } //  if_else   
     } //  for   
       
     return  res;  
}   
 
 //  加载pe到内存并对齐所有节   
 BOOL AlignPEToMem(  void   * Buf  
                  ,  long  Len  
                  , PIMAGE_NT_HEADERS  & peH  
                  , PIMAGE_SECTION_HEADERS  & peSecH  
                  ,  void   *& Mem  
                  , unsigned  long   & ImageSize)  
  {  
    PIMAGE_DOS_HEADER SrcMz; //  DOS头   
     PIMAGE_NT_HEADERS SrcPeH; //  PE头   
     PIMAGE_SECTION_HEADERS SrcPeSecH; //  节表   
       
    SrcMz  =  (PIMAGE_DOS_HEADER)Buf;  
 
     if ( Len  <   sizeof (IMAGE_DOS_HEADER) )   
         return  FALSE;  
      
     if ( SrcMz -> e_magic  !=  IMAGE_DOS_SIGNATURE )  
         return  FALSE;  
      
     if ( Len  <  SrcMz -> e_lfanew  +  ( long ) sizeof (IMAGE_NT_HEADERS) )  
         return  FALSE;  
 
    SrcPeH  =  (PIMAGE_NT_HEADERS)(( int )SrcMz  +  SrcMz -> e_lfanew);  
     if ( SrcPeH -> Signature  !=  IMAGE_NT_SIGNATURE )  
         return  FALSE;  
 
     if ( (SrcPeH -> FileHeader.Characteristics  &  IMAGE_FILE_DLL)  ||   
        (SrcPeH -> FileHeader.Characteristics  &  IMAGE_FILE_EXECUTABLE_IMAGE  ==   0 )  ||   
        (SrcPeH -> FileHeader.SizeOfOptionalHeader  !=   sizeof (IMAGE_OPTIONAL_HEADER)) )  
      {  
         return  FALSE;  
    }   
 
 
    SrcPeSecH  =  (PIMAGE_SECTION_HEADERS)(( int )SrcPeH  +   sizeof (IMAGE_NT_HEADERS));  
    ImageSize  =  CalcTotalImageSize( SrcMz, Len, SrcPeH, SrcPeSecH);  
 
     if ( ImageSize  ==   0  )  
         return  FALSE;  
      
    Mem  =  VirtualAlloc( NULL, ImageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);  //  分配内存   
      if ( Mem  !=  NULL )  
      {  
         //  计算需要复制的PE头字节数   
         unsigned  long  l  =  SrcPeH -> OptionalHeader.SizeOfHeaders;  
         for (  int  i  =   0 ; i  <  SrcPeH -> FileHeader.NumberOfSections;  ++ i)  
          {  
             if ( (SrcPeSecH[i] -> PointerToRawData)  &&   
                (SrcPeSecH[i] -> PointerToRawData  <  l) )  
              {  
                l  =  SrcPeSecH[i] -> PointerToRawData;  
            }   
        }   
        memmove( Mem, SrcMz, l);  
        peH  =  (PIMAGE_NT_HEADERS)(( int )Mem  +  ((PIMAGE_DOS_HEADER)Mem) -> e_lfanew);  
        peSecH  =  (PIMAGE_SECTION_HEADERS)(( int )peH  +   sizeof (IMAGE_NT_HEADERS));  
 
         void   * Pt  =  ( void   * )((unsigned  long )Mem   
             +  GetAlignedSize( peH -> OptionalHeader.SizeOfHeaders  
            , peH -> OptionalHeader.SectionAlignment)  
            );  
 
         for ( i  =   0 ; i  <  peH -> FileHeader.NumberOfSections;  ++ i)  
          {  
             //  定位该节在内存中的位置   
              if (peSecH[i] -> VirtualAddress)  
                Pt  =  ( void   * )((unsigned  long )Mem  +  peSecH[i] -> VirtualAddress);  
 
             if (peSecH[i] -> SizeOfRawData)  
              {  
                 //  复制数据到内存   
                 memmove(Pt, ( const   void   * )((unsigned  long )(SrcMz)  +  peSecH[i] -> PointerToRawData), peSecH[i] -> SizeOfRawData);  
                 if (peSecH[i] -> Misc.VirtualSize  <  peSecH[i] -> SizeOfRawData)  
                    Pt  =  ( void   * )((unsigned  long )Pt  +  GetAlignedSize(peSecH[i] -> SizeOfRawData, peH -> OptionalHeader.SectionAlignment));  
                 else   //  pt 定位到下一节开始位置   
                     Pt  =  ( void   * )((unsigned  long )Pt  +  GetAlignedSize(peSecH[i] -> Misc.VirtualSize, peH -> OptionalHeader.SectionAlignment));  
            }   
             else  
              {  
                Pt  =  ( void   * )((unsigned  long )Pt  +  GetAlignedSize(peSecH[i] -> Misc.VirtualSize, peH -> OptionalHeader.SectionAlignment));  
            }   
        }   
    }   
     return  TRUE;  
}   
 
   
typedef  void   * (__stdcall  * pfVirtualAllocEx)(unsigned  long ,  void   * , unsigned  long , unsigned  long , unsigned  long );  
pfVirtualAllocEx MyVirtualAllocEx  =  NULL;  
 
BOOL IsNT()  
  {  
     return  MyVirtualAllocEx != NULL;  
}   
 
 //  生成外壳程序命令行   
 char   * PrepareShellExe( char   * CmdParam, unsigned  long  BaseAddr, unsigned  long  ImageSize)  
  {  
     if (IsNT())  
      {  
         char   * Buf  =   new   char [ 256 ];  
        memset(Buf,  0 ,  256 );  
        GetModuleFileName( 0 , Buf,  256 );  
        strcat(Buf, CmdParam);  
         return  Buf;  //  请记得释放内存;-)   
     }   
     else  
      {  
         //  Win98下的处理请参考原文;-)  
         //   http://community.csdn.net/Expert/topic/4416/4416252.xml?temp=8.709133E-03    
          return  NULL;  
    }   
}   
 
 //  是否包含可重定向列表   
 BOOL HasRelocationTable(PIMAGE_NT_HEADERS peH)  
  {  
     return  (peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)  
         &&  (peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size);  
}   
 
#pragma pack(push,  1 )  
typedef  struct  {  
    unsigned  long  VirtualAddress;  
    unsigned  long  SizeOfBlock;  
}   * PImageBaseRelocation;  
#pragma pack(pop)  
 
 //  重定向PE用到的地址   
 void  DoRelocation(PIMAGE_NT_HEADERS peH,  void   * OldBase,  void   * NewBase)  
  {  
    unsigned  long  Delta  =  (unsigned  long )NewBase  -  peH -> OptionalHeader.ImageBase;  
    PImageBaseRelocation p  =  (PImageBaseRelocation)((unsigned  long )OldBase   
         +  peH -> OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);  
     while (p -> VirtualAddress  +  p -> SizeOfBlock)  
      {  
        unsigned  short   * pw  =  (unsigned  short   * )(( int )p  +   sizeof ( * p));  
         for (unsigned  int  i = 1 ; i  <=  (p -> SizeOfBlock  -   sizeof ( * p))  /   2 ;  ++ i)  
          {  
             if (( * pw)  &   0xF000   ==   0x3000 )  {  
                unsigned  long   * t  =  (unsigned  long   * )((unsigned  long )(OldBase)  +  p -> VirtualAddress  +  (( * pw)  &   0x0FFF ));  
                 * t  +=  Delta;  
            }   
             ++ pw;  
        }   
        p  =  (PImageBaseRelocation)pw;  
    }   
}   
 
 //  卸载原外壳占用内存   
 BOOL UnloadShell(HANDLE ProcHnd, unsigned  long  BaseAddr)  
  {  
    typedef unsigned  long  (__stdcall  * pfZwUnmapViewOfSection)(unsigned  long , unsigned  long );  
    pfZwUnmapViewOfSection ZwUnmapViewOfSection  =  NULL;  
    BOOL res  =  FALSE;  
    HMODULE m  =  LoadLibrary( " ntdll.dll " );  
     if (m)  {  
        ZwUnmapViewOfSection  =  (pfZwUnmapViewOfSection)GetProcAddress(m,  " ZwUnmapViewOfSection " );  
         if (ZwUnmapViewOfSection)  
            res  =  (ZwUnmapViewOfSection((unsigned  long )ProcHnd, BaseAddr)  ==   0 );  
        FreeLibrary(m);  
    }   
     return  res;  
}   
 
 //  创建外壳进程并获取其基址、大小和当前运行状态   
 BOOL CreateChild( char   * Cmd, CONTEXT  & Ctx, HANDLE  & ProcHnd, HANDLE  & ThrdHnd,   
                 unsigned  long   & ProcId, unsigned  long   & BaseAddr, unsigned  long   & ImageSize)  
  {  
    STARTUPINFOA si;  
    PROCESS_INFORMATION pi;  
    unsigned  long  old;  
    MEMORY_BASIC_INFORMATION MemInfo;  
    memset( & si,  0 ,  sizeof (si));  
    memset( & pi,  0 ,  sizeof (pi));  
    si.cb  =   sizeof (si);  
      
    BOOL res  =  CreateProcess(NULL, Cmd, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL,  & si,  & pi);  //  以挂起方式运行进程;   
       if (res)  {  
        ProcHnd  =  pi.hProcess;  
        ThrdHnd  =  pi.hThread;  
        ProcId  =  pi.dwProcessId;  
         //  获取外壳进程运行状态,[ctx.Ebx+8]内存处存的是外壳进程的加载基址,ctx.Eax存放有外壳进程的入口地址   
         Ctx.ContextFlags  =  CONTEXT_FULL;  
        GetThreadContext(ThrdHnd,  & Ctx);  
        ReadProcessMemory(ProcHnd, ( void   * )(Ctx.Ebx + 8 ),  & BaseAddr,  sizeof (unsigned  long ),  & old);  //  读取加载基址   
          void   * p  =  ( void   * )BaseAddr;  
         //  计算外壳进程占有的内存   
          while (VirtualQueryEx(ProcHnd, p,  & MemInfo,  sizeof (MemInfo)))  
          {  
             if (MemInfo.State  =  MEM_FREE)  break ;  
            p  =  ( void   * )((unsigned  long )p  +  MemInfo.RegionSize);  
        }   
        ImageSize  =  (unsigned  long )p  -  (unsigned  long )BaseAddr;  
    }   
     return  res;  
}   
 
 //  创建外壳进程并用目标进程替换它然后执行   
 HANDLE AttachPE( char   * CmdParam, PIMAGE_NT_HEADERS peH, PIMAGE_SECTION_HEADERS peSecH,   
                 void   * Ptr, unsigned  long  ImageSize, unsigned  long   & ProcId)  
  {  
    HANDLE res  =  INVALID_HANDLE_VALUE;  
    CONTEXT Ctx;  
    HANDLE Thrd;  
    unsigned  long  Addr, Size;  
     char   * s  =  PrepareShellExe(CmdParam, peH -> OptionalHeader.ImageBase, ImageSize);  
     if (s == NULL)  return  res;  
     if (CreateChild(s, Ctx, res, Thrd, ProcId, Addr, Size))  {  
         void   * p  =  NULL;  
        unsigned  long  old;  
         if ((peH -> OptionalHeader.ImageBase  ==  Addr)  &&  (Size  >=  ImageSize))  { //  外壳进程可以容纳目标进程并且加载地址一致   
             p  =  ( void   * )Addr;  
            VirtualProtectEx(res, p, Size, PAGE_EXECUTE_READWRITE,  & old);  
        }   
         else   if (IsNT())  {  
             if (UnloadShell(res, Addr))  { //  卸载外壳进程占有内存   
                 p  =  MyVirtualAllocEx((unsigned  long )res, ( void   * )peH -> OptionalHeader.ImageBase, ImageSize, MEM_RESERVE  |  MEM_COMMIT, PAGE_EXECUTE_READWRITE);  
            }   
             if ((p  ==  NULL)  &&  HasRelocationTable(peH))  { //  分配内存失败并且目标进程支持重定向   
                 p  =  MyVirtualAllocEx((unsigned  long )res, NULL, ImageSize, MEM_RESERVE  |  MEM_COMMIT, PAGE_EXECUTE_READWRITE);  
                 if (p) DoRelocation(peH, Ptr, p);  //  重定向   
             }   
        }   
         if (p)  {  
            WriteProcessMemory(res, ( void   * )(Ctx.Ebx + 8 ),  & p,  sizeof (DWORD),  & old);  //  重置目标进程运行环境中的基址   
             peH -> OptionalHeader.ImageBase  =  (unsigned  long )p;  
             if (WriteProcessMemory(res, p, Ptr, ImageSize,  & old))  { //  复制PE数据到目标进程   
                 Ctx.ContextFlags  =  CONTEXT_FULL;  
                 if ((unsigned  long )p  ==  Addr)  
                    Ctx.Eax  =  peH -> OptionalHeader.ImageBase  +  peH -> OptionalHeader.AddressOfEntryPoint;  //  重置运行环境中的入口地址   
                  else  
                    Ctx.Eax  =  (unsigned  long )p  +  peH -> OptionalHeader.AddressOfEntryPoint;  
                SetThreadContext(Thrd,  & Ctx); //  更新运行环境   
                 ResumeThread(Thrd); //  执行   
                 CloseHandle(Thrd);  
            }   
             else  { //  加载失败,杀掉外壳进程   
                 TerminateProcess(res,  0 );  
                CloseHandle(Thrd);  
                CloseHandle(res);  
                res  =  INVALID_HANDLE_VALUE;  
            }   
        }   
         else  { //  加载失败,杀掉外壳进程   
             TerminateProcess(res,  0 );  
            CloseHandle(Thrd);  
            CloseHandle(res);  
            res  =  INVALID_HANDLE_VALUE;  
        }   
    }   
    delete[] s;  
     return  res;  
}   
 
  /**/ /**/ /**/ /* ******************************************************/ 
{ ******************************************************* } 
{ *                 从内存中加载并运行exe               * } 
{ ******************************************************* } 
{ * 参数:                                                } 
{ * Buffer: 内存中的exe地址                               } 
{ * Len: 内存中exe占用长度                                } 
{ * CmdParam: 命令行参数(不包含exe文件名的剩余命令行参数)} 
{ * ProcessId: 返回的进程Id                               } 
{ * 返回值: 如果成功则返回进程的Handle(ProcessHandle),   } 
{            如果失败则返回INVALID_HANDLE_VALUE           } 
{ ******************************************************* } 
 /****************************************************** */  
HANDLE MemExecute( void   * ABuffer,  long  Len,  char   * CmdParam, unsigned  long   * ProcessId)  
  {  
    HANDLE res  =  INVALID_HANDLE_VALUE;  
    PIMAGE_NT_HEADERS peH;  
    PIMAGE_SECTION_HEADERS peSecH;  
     void   * Ptr;  
    unsigned  long  peSz;  
     if (AlignPEToMem(ABuffer, Len, peH, peSecH, Ptr, peSz))  
      {  
        res  =  AttachPE(CmdParam, peH, peSecH, Ptr, peSz,  * ProcessId);  
        VirtualFree(Ptr, peSz, MEM_DECOMMIT);  
    }   
     return  res;  
}   
 
 //  初始化   
 class  CInit  
  {  
 public :  
    CInit()  
      {  
        MyVirtualAllocEx  =  (pfVirtualAllocEx)GetProcAddress(GetModuleHandle( " Kernel32.dll " ),  " VirtualAllocEx " );  
    }   
} Init;  
 
 int  main( int  argc,  char *  argv[])
  {
    FILE *  fp;
    fp  =  fopen( " E://CProject//DBGVIEW.EXE " , " rb " );
 if  ( fp )
      {

        fseek(fp, 0l ,SEEK_END);
         int  file_size = ftell(fp); /**/ /* 获取文件长度 */
         fseek(fp, 0l ,SEEK_SET); /**/ /* 回到文件头部 */   
       
       
        LPBYTE pBuf  =   new  BYTE[file_size];  
        memset( pBuf,  0 , file_size); 

        fread(pBuf,file_size, 1 ,fp);

        DWORD id  =  GetCurrentProcessId();
        unsigned  long  ulProcessId  =   0 ;  
        MemExecute( pBuf, file_size,  "" ,  & ulProcessId);  
        delete[] pBuf;  
       
    }  
   
     return   0 ;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/388863.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

srpg 胜利条件设定_英雄联盟获胜条件

srpg 胜利条件设定介绍 (Introduction) The e-sports community has been growing rapidly in the past few years, and what used to be a casual pastime has morphed into an industry projected to generate $1.8 B in revenue by 2022. While there are many video games …

[Egret][文档]遮罩

——遮罩的作用是指定一个显示对象的可见区域&#xff0c;即这个显示对象只在这个区域可见。 一、矩形遮罩 将一个矩形对象赋值给显示对象的 mask 属性。 shp.mask new egret.Rectangle(20,20,30,50); 【注】&#xff1a;这个矩形的坐标(20,20)和(30,50)是相对于被遮罩对象shp…

clob类型字段最大存储长度_请教oracle的CLOB字段的最大长度?

CLOB和BLOB都是4G&#xff0c;而LONG ,LONG raw是旧时代的oracle二进制和长文本表示&#xff0c;将来会被废弃。最长长度是2G.单位是Byte表中单个 LOB 字段 在 9i 版本中可保存 4GB 数据, 在 10g 版本中可保存多达 128TB 的数据.所以理论上是没限制的ORACLE的数据类型-- ORAC…

JdbcUtil

转自&#xff1a;https://github.com/ghyg525/util_java_jdbc JdbcUtil.java import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; …

机器学习 综合评价_PyCaret:机器学习综合

机器学习 综合评价Any Machine Learning project journey starts with loading the dataset and ends (continues ?!) with the finalization of the optimum model or ensemble of models for predictions on unseen data and production deployment.任何机器学习项目的旅程都…

silverlight 3D 游戏开发

http://www.postvision.net/SilverMotion/DemoTech.aspx silverlight 3D 游戏开发 时间:2010-10-22 06:33来源:开心银光 作者:黎东海 点击: 562次意外发现一个silverlight的实时3D渲染引擎。性能比开源那些强很多。 而且支持直接加载maya,3Dmax等主流3D模型文件。 附件附上它的…

redis终端简单命令

keys * 获取所有键lRange hongbao:44 0 -1获取该键的所有值del hongbao:44 删除该键的所有值 hgetAll user:44 获取该键的所有队列hget hongbao:44 8 获取该队列用户为8的值hset hongbao:44 7 asdf设置该队列用户为7的值hdel user:44 8 删除该队列用户为8的值 flushall 清空red…

python中ix用法_Python中使用ix的数据帧子集

您可以使用X[var2].iloc[[0,1]]&#xff1a;In [280]: X[var2].iloc[[0,1]]Out[280]:0 NaN4 9Name: var2, dtype: float64由于X[var2]是X的视图&#xff0c;因此X[var2].iloc[[0,1]]对两者都是安全的访问和分配。但是如果你使用这种“链式索引”要小心模式(例如这里使用的index…

LintCode 16. 带重复元素的排列

写在前面&#xff1a;这题和全排列不含重复元素的那题几乎一样&#xff0c;我比较垃圾&#xff0c;就用HashSet去掉了重复的元素但是看了九章算法的答案也没看懂&#xff0c;他写的很有感觉。 用了hash&#xff0c;本来想着怎么写hashcode()和equal()方法的&#xff0c;哪知道都…

皮尔逊相关系数 相似系数_皮尔逊相关系数

皮尔逊相关系数 相似系数数据科学和机器学习统计 (STATISTICS FOR DATA SCIENCE AND MACHINE LEARNING) In the last post, we analyzed the relationship between categorical variables and categorical and continuous variables. In this case, we will analyze the relati…

【洛谷】P1641 [SCOI2010]生成字符串(思维+组合+逆元)

题目 传送门&#xff1a;QWQ 分析 不想画图。 https://www.luogu.org/problemnew/solution/P1641 好神仙的题啊。 代码 1 // luogu-judger-enable-o22 #include <bits/stdc.h>3 using namespace std;4 typedef long long ll;5 const int maxn15000000;6 const ll MOD2010…

Kubernetes持续交付-Jenkins X的Helm部署

Jenkins X 是一个集成化的 CI / CD 平台&#xff0c;可用于 部署在Kubernetes集群或云计算中心。支持在云计算环境下简单地开发和部署应用。本项目是在Kubernetes上的安装支持工具集。 本工具集中包含&#xff1a; Jenkins - 定制好的流水线和运行环境&#xff0c;完全整合CI/C…

中国石油大学(华东)暑期集训--二进制(BZOJ5294)【线段树】

问题 C: 二进制 时间限制: 1 Sec 内存限制: 128 MB提交: 8 解决: 2[提交] [状态] [讨论版] [命题人:]题目描述 pupil发现对于一个十进制数&#xff0c;无论怎么将其的数字重新排列&#xff0c;均不影响其是不是3的倍数。他想研究对于二进制&#xff0c;是否也有类似的性质。于…

2018年10个最佳项目管理工具及链接

要在任何业务中取得成功&#xff0c;对项目进行适当的管理非常重要。 项目管理是一系列活动&#xff0c;包括计划&#xff0c;执行&#xff0c;控制和完成项目。项目管理工具有助于简化此过程。这里是Best 10项目管理工具及其功能和下载链接的精选列表。1&#xff09;AsanaAsan…

Java 8 新特性之Stream API

1. 概述 1.1 简介 Java 8 中有两大最为重要的改革&#xff0c;第一个是 Lambda 表达式&#xff0c;另外一个则是 Stream API&#xff08;java.util.stream.*&#xff09;。 Stream 是 Java 8 中处理集合的关键抽象概念&#xff0c;它可以指定你希望对集合进行的操作&#xff0c…

[Python设计模式] 第17章 程序中的翻译官——适配器模式

github地址:https://github.com/cheesezh/python_design_patterns 适配器模式 适配器模式&#xff0c;将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作[DP]。 当系统的数据和行为都正确&#xff0c;但是接口…

Ubuntu中NS2安装详细教程

前言&#xff1a; NS2是指 Network Simulator version 2&#xff0c;NS&#xff08;Network Simulator&#xff09; 是一种针对网络技术的源代码公开的、免费的软件模拟平台&#xff0c;研究人员使用它可以很容易的进行网络技术的开发&#xff0c;而且发展到今天&#xff0c;它…

es6核心特性图

转载于:https://juejin.im/post/5c19e188e51d452db4753925

带你利用一句话完成转场动画

这篇文章主要给大家介绍了关于iOS如何利用一句话完成转场动画的相关资料&#xff0c;文中通过示例代码介绍的非常详细&#xff0c;对大家的学习或者工作具有一定的参考学习价值&#xff0c;需要的朋友们下面来一起学习学习吧前言本文介绍SS_AnimationTransition 的使用方法,利用…

14.vue路由脚手架

一.vue路由&#xff1a;https://router.vuejs.org/zh/ 1、定义 let router new VueRouter({mode:"history/hash",base:"基本路径" 加一些前缀 必须在history模式下有效linkActiveClass:"active", 范围选择linkExactActiveClass:"exact&qu…