几种常用的保护应用程序的方法,编写成类库

保护用户数据和应用程序安全(iOS中的安全机制) iOS作为Apple公司推出的移动操作系统,以其强大的安全性和用户隐私保护能力而闻名。iOS中的安全机制是一个多层次、全方位的体系,旨在保护用户数据和应用程序免受各种威胁。以下将详细阐述iOS中的安全机制以及保护用户数据和应用程序安全的具体措施。 阅读详情
几种常用的保护应用程序的方法 ( 作者:老实和尚  coverlove@163.com )



1、前言
  目前很多程序员都没有软件安全的意识,对自己辛辛苦苦的劳动成果不加保护,而这些缺乏保护意识的程序在日益强大的SoftIce, OllyDBG(OllyICE), W32DASM等工具面前显得如此脆弱,一个稍微有点经验的Cracker可能在几分钟之内就可以轻易的突破防线;有些程序员虽然有了保护自己程序的意识,但是一般都完全依赖于专业的保护软件进行加壳保护,对自己的程序本身在编码阶段却完全不设防,而这些知名的壳也并非安全,目前对这些知名的壳都有专门的脱壳工具和脱壳教材,一旦这些壳被剥掉,那么呈现在Cracker面前的也完全是一些赤裸裸的代码。
  本文主要介绍在软件编码阶段进行一些必要的保护手段,在编译生成二进制代码后再进行外部加壳保护处理,这样应该更安全一些,一旦壳被攻破,还有内部的保护机制在起作用,已经写成类库,觉得有用的可以下载稍微修改即可使用。

2、常用的几种编码阶段的保护手段

A、检测SoftIce驱动是否安装

检测SoffIce的驱动是否存在来判断是否安装了SoftIce,代码如下:

if(CreateFile( "////.//NTICE", GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
        NULL)!=INVALID_HANDLE_VALUE) 
  { 
      There is SoftICE NT on your system; 
  } 
if(CreateFile( "////.//SICE", GENERIC_READ | GENERIC_WRITE, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, 
        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
        NULL)!=INVALID_HANDLE_VALUE) 
  { 
      There is SoftICE98 on your system; 
  }


B. 程序窗口句柄检测
  
检测是否存在窗口Ollyice或者OllyDbg等等,读者可以自行添加

char name1[]="OLLYDBG";

char name2[]="OLLYICE";

HWND hwnd=BlurFindWindow(name1); //循环检测windows所有顶层窗口,只要窗口名称中含有(模糊匹配)字符串name1,name2的窗口则说明存在Ollyice或者OllyDbg

if(hwnd!=NULL)
{
  There is OLLYDBG on your system;
}
hwnd=BlurFindWindow(name2);

if(hwnd!=NULL)
{
  There is OLLYICE on your system;
}

C. 用线程环境块检测

TEB(Thread Environment Block) 在 Windows 9x 系列中被称为 TIB(Thread Information Block),它记录了线程的重要信息,而且每一个线程都会对应一个 TEB 结构。在TEB结构的 30h 偏移处存放着另外一个重要的数据结构的首地址PPEB:
typedef struct _NT_TEB
{
 NT_TIB Tib; // 00h
 PVOID EnvironmentPointer; // 1Ch
 CLIENT_ID Cid; // 20h
 PVOID ActiveRpcInfo; // 28h
 PVOID ThreadLocalStoragePointer; // 2Ch
 PPEB Peb; // 30h
 ULONG LastErrorValue; // 34h
 ULONG CountOfOwnedCriticalSections; // 38h
 PVOID CsrClientThread; // 3Ch
 PVOID Win32ThreadInfo; // 40h
 ULONG Win32ClientInfo[0x1F]; // 44h
 PVOID WOW32Reserved; // C0h
 ULONG CurrentLocale; // C4h
 ULONG FpSoftwareStatusRegister; // C8h
 PVOID SystemReserved1[0x36]; // CCh
 PVOID Spare1; // 1A4h
 LONG ExceptionCode; // 1A8h
 ULONG SpareBytes1[0x28]; // 1ACh
 PVOID SystemReserved2[0xA]; // 1D4h
 GDI_TEB_BATCH GdiTebBatch; // 1FCh
 ULONG gdiRgn; // 6DCh
 ULONG gdiPen; // 6E0h
 ULONG gdiBrush; // 6E4h
 CLIENT_ID RealClientId; // 6E8h
 PVOID GdiCachedProcessHandle; // 6F0h
 ULONG GdiClientPID; // 6F4h
 ULONG GdiClientTID; // 6F8h
 PVOID GdiThreadLocaleInfo; // 6FCh
 PVOID UserReserved[5]; // 700h
 PVOID glDispatchTable[0x118]; // 714h
 ULONG glReserved1[0x1A]; // B74h
 PVOID glReserved2; // BDCh
 PVOID glSectionInfo; // BE0h
 PVOID glSection; // BE4h
 PVOID glTable; // BE8h
 PVOID glCurrentRC; // BECh
 PVOID glContext; // BF0h
 NTSTATUS LastStatusValue; // BF4h
 UNICODE_STRING StaticUnicodeString; // BF8h
 WCHAR StaticUnicodeBuffer[0x105]; // C00h
 PVOID DeallocationStack; // E0Ch
 PVOID TlsSlots[0x40]; // E10h
 LIST_ENTRY TlsLinks; // F10h
 PVOID Vdm; // F18h
 PVOID ReservedForNtRpc; // F1Ch
 PVOID DbgSsReserved[0x2]; // F20h
 ULONG HardErrorDisabled; // F28h
 PVOID Instrumentation[0x10]; // F2Ch
 PVOID WinSockData; // F6Ch
 ULONG GdiBatchCount; // F70h
 ULONG Spare2; // F74h
 ULONG Spare3; // F78h
 ULONG Spare4; // F7Ch
 PVOID ReservedForOle; // F80h
 ULONG WaitingOnLoaderLock; // F84h

 PVOID StackCommit; // F88h
 PVOID StackCommitMax; // F8Ch
 PVOID StackReserve; // F90h

 PVOID MessageQueue; // ???
} NT_TEB, *PNT_TEB; 


PPEB  Peb;       // 30h Pointer to owning process database

这个偏移地址处的内容非常有用,它指向本线程的拥有者的 PEB(Process Database) 的线性地址。这个结构的02h 偏移处存放着进程是否被调试的标志。当有调试器调试进程时这个BeingDebugged会被置1,否则为0,可以通过这个标志来检测是否被调试器调试。

typedef struct _PEB
{
      UCHAR InheritedAddressSpace;                     // 00h
      UCHAR ReadImageFileExecOptions;                  // 01h
      UCHAR BeingDebugged;                             // 02h
      UCHAR Spare;                                     // 03h
      PVOID Mutant;                                    // 04h
      PVOID ImageBaseAddress;                          // 08h
      PPEB_LDR_DATA Ldr;                               // 0Ch
      PRTL_USER_PROCESS_PARAMETERS ProcessParameters;  // 10h
      PVOID SubSystemData;                             // 14h
      PVOID ProcessHeap;                               // 18h
      PVOID FastPebLock;                               // 1Ch
      PPEBLOCKROUTINE FastPebLockRoutine;              // 20h
      PPEBLOCKROUTINE FastPebUnlockRoutine;            // 24h
      ULONG EnvironmentUpdateCount;                    // 28h
      PVOID* KernelCallbackTable;                      // 2Ch
      PVOID EventLogSection;                           // 30h
      PVOID EventLog;                                  // 34h
      PPEB_FREE_BLOCK FreeList;                        // 38h
      ULONG TlsExpansionCounter;                       // 3Ch
      PVOID TlsBitmap;                                 // 40h
      ULONG TlsBitmapBits[0x2];                        // 44h
      PVOID ReadOnlySharedMemoryBase;                  // 4Ch
      PVOID ReadOnlySharedMemoryHeap;                  // 50h
      PVOID* ReadOnlyStaticServerData;                 // 54h
      PVOID AnsiCodePageData;                          // 58h
      PVOID OemCodePageData;                           // 5Ch
      PVOID UnicodeCaseTableData;                      // 60h
      ULONG NumberOfProcessors;                        // 64h
      ULONG NtGlobalFlag;                              // 68h
      UCHAR Spare2[0x4];                               // 6Ch
      LARGE_INTEGER CriticalSectionTimeout;            // 70h
      ULONG HeapSegmentReserve;                        // 78h
      ULONG HeapSegmentCommit;                         // 7Ch
      ULONG HeapDeCommitTotalFreeThreshold;            // 80h
      ULONG HeapDeCommitFreeBlockThreshold;            // 84h
      ULONG NumberOfHeaps;                             // 88h
      ULONG MaximumNumberOfHeaps;                      // 8Ch
      PVOID** ProcessHeaps;                            // 90h
      PVOID GdiSharedHandleTable;                      // 94h
      PVOID ProcessStarterHelper;                      // 98h
      PVOID GdiDCAttributeList;                        // 9Ch
      PVOID LoaderLock;                                // A0h
      ULONG OSMajorVersion;                            // A4h
      ULONG OSMinorVersion;                            // A8h
      ULONG OSBuildNumber;                             // ACh
      ULONG OSPlatformId;                              // B0h
      ULONG ImageSubSystem;                            // B4h
      ULONG ImageSubSystemMajorVersion;                // B8h
      ULONG ImageSubSystemMinorVersion;                // C0h
      ULONG GdiHandleBuffer[0x22];                     // C4h

      PVOID ProcessWindowStation;                      
} PEB, *PPEB;
代码如下:
int exist=0;
__asm
  {
    pushad
    //在fs:[0x18]再加上0x30就是指向了TEB结构
    mov   eax,fs:[0x18]     //pTeb 线性地址
        mov   eax, dword ptr  [eax+0x30]    //pPeb的首地址
    //获取PEB偏移2h处BeingDebugged的值  
    movzx eax,byte ptr[eax+0x02]
    or al,al  
    jz No
    jnz Yes
     No:
     mov exist,0
     jmp Exit
     Yes:
     mov exist,1

     jmp Exit
     Exit:    
    popad
  }  
  if(exist)
  {
    // The process is debugged

  }

D、用API函数IsDebuggerPresent检测

if(IsDebuggerPresent())
{
  // The process is debugged

}

E、利用异常SEH机制

利用异常检测调试器,下面这段代码执行throw(&exce)
的时候会抛出异常,然后进入到我们设置好的异常处理例程将bIsInDebugger设置为FALSE,而一旦调试器运行这段代码的时候,异常首先被调试器截获,如果调试器截获后进行了处理而没有继续传递给我们的异常处理例程,那么将不会执行bIsInDebugger=FALSE从而达到检测调试器的目的。

BOOL bIsInDebugger = TRUE ;
 
CFileException exce;

try
{
     // 抛出异常 
    
    throw(&exce);

    //throw(1);

}
catch(int )
{
  bIsInDebugger = TRUE ;

}
catch(CFileException *)
{
  
  bIsInDebugger = FALSE ;
}

  
if( bIsInDebugger )
{
  // The process is debugged

}

F、使用自己的函数替代部分系统函数,完成同样的功能

  比如:替换上面的IsDebuggerPresent函数,拷贝IsDebuggerPresent函数的实现代码为自己所用,这样可以避免Cracker使用bpx IsDebuggerPresent断点来跟踪我们的程序。偷系统的代码实现如下:

名称:  11.jpg
查看次数: 430
文件大小:  77.5 KB

 
(系统API IsDebuggerPresent实现的二进制代码 )

__declspec( naked )  BOOL CDebugProtect::IsDebuggerPresentEx()
{
  __asm
  {
    mov     eax, dword ptr fs:[18h]
    mov     eax, dword ptr [eax+30h]
    movzx   eax, byte ptr [eax+2h]
    retn
  }
}
这样在调用IsDebuggerPresent的地方都可以用IsDebuggerPresentEx替换掉。当然有些函数只能替换高层API,对于底层API还是无法替换的,这样Cracker可以在更底层的API上面下断点,再跟踪到调用的地方。


G、使用动态获取DLL函数地址替代使用隐式调用DLL
隐式调用DLL中函数的地方,很容易让Crack通过引用API参考找到下断点的地方,Cracker只需要简单的双击引用API地址的行就能定位到调用API的地方。

DWORD CDebugProtect::TerminateFun=GetProcAddr("kernel32.dll","TerminateProcess");

DWORD CDebugProtect::GetProcAddr(const char *dll,const char *fun)
{
  //const char * pszModName = "kernel32.dll";

  //const char * pszTerminatelName = "TerminateProcess";

  const char * pszModName=dll;

  const char * pszTerminatelName =fun;


  HMODULE hKernel = GetModuleHandle(pszModName);
  
  FARPROC proc=GetProcAddress(hKernel,pszTerminatelName);

  return (DWORD)proc;

}

如在类的静态变量中获取TerminateProcess函数的地址,然后在调用TerminateProcess的地方使用这个变量来终止进程,这样Cracker就不能简单的下断点bpx TerminateProcess。

如下:在类的静态变量初始化时候完成API地址的获取,在实际使用的时候使用这个地址直接CALL,下面是两个API地址隐藏的实现方法。

DWORD apiAddr=TerminateFun; // TerminateFun是一个静态变量,在类第一次使用前已经被初始化

HANDLE currentp=GetCurrentProcess(); //当前进程句柄

  _asm
{
      pushad

      push 0
      
      push currentp

      call apiAddr //形成的汇编代码就很难通过函数参考来找到

      popad


}

//获取硬盘ID,通过隐藏API地址调用
DWORD   GenerateID(void)
{
  const char * lpRootPathName="c://";   //取C盘的序列号

  char lpVolumeNameBuffer[12];  //磁盘卷标

  unsigned long int nVolumeNameSize=12;
  
  unsigned long int VolumeSerialNumber;  //磁盘序列号
  unsigned long int MaximumComponentLength;
  char  lpFileSystemNameBuffer[10];
  unsigned long int nFileSystemNameSize=10;
  unsigned long int FileSystemFlags;

  DWORD apiAddr=GetVolumeInformationFun;

  __asm
  {
    pushad  

    push nFileSystemNameSize

    lea eax, lpFileSystemNameBuffer
    
    push eax

    lea eax, FileSystemFlags  

    push eax

    lea eax, MaximumComponentLength 

    push eax

    lea eax, VolumeSerialNumber 

    push eax

    push nVolumeNameSize

    lea eax, lpVolumeNameBuffer 
    
    push eax

    push lpRootPathName //常量字符串变量本身就代表地址,直接使用即可不再使用lea

    call apiAddr

    popad 

  }

//原来的调用方式

//  GetVolumeInformation(lpRootPathName,
//    lpVolumeNameBuffer, nVolumeNameSize,
//    &VolumeSerialNumber, &MaximumComponentLength,
//    &FileSystemFlags,
//    lpFileSystemNameBuffer, nFileSystemNameSize);

  VolumeSerialNumber^=0x12345678;

  return  VolumeSerialNumber;  //给用户显示机器码使用,硬盘伪序列号
  
}

H、 检查程序的父进程是否为EXPLORER.EXE
一个正常的EXE文件应该是由EXPLORER.EXE来加载的,所以其父进程应该是EXPLORER.EXE,可以通过这个检测点来检测是否被调试。

char lpszSystemInfo[MAX_PATH];
HANDLE hSnapshot=NULL;

  DWORD PID_child;
  DWORD PID_parent,PID_explorer;
  HANDLE hh_parnet = NULL;
    PROCESSENTRY32  pe32 = {0};
  pe32.dwSize = sizeof(PROCESSENTRY32);//0x128;
    PID_child=GetCurrentProcessId();//getpid();
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
  if (Process32First(hSnapshot, &pe32))
    {
    while (Process32Next(hSnapshot, &pe32))
    {
      GetFileNameFromPath(pe32.szExeFile);
            CharUpperBuff(pe32.szExeFile,strlen(pe32.szExeFile));
            if(strcmp(pe32.szExeFile,"EXPLORER.EXE")==0)
            {
                PID_explorer=pe32.th32ProcessID;
            }
      if(pe32.th32ProcessID==PID_child)
      {
        PID_parent=pe32.th32ParentProcessID;
      }
    }
  }
    if(PID_parent!=PID_explorer)
    {
        hh_parnet= OpenProcess(PROCESS_ALL_ACCESS, TRUE, PID_parent);
    res=TRUE;  
        //TerminateProcess(hh_parnet, 0);

     _asm
     {
      pushad
      push 0    
      push hh_parnet
      call apiAddr
      popad
     }
    }
  else
  {
    MODULEENTRY32  me32 = {0};
    me32.dwSize = sizeof(MODULEENTRY32);
    hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE,PID_explorer);
    if (Module32First(hSnapshot, &me32))
    {
        do
            {
          if(PID_explorer==me32.th32ProcessID)
          {
          GetWindowsDirectory(lpszSystemInfo, MAX_PATH+1);
          strcat(lpszSystemInfo,"//");
          strcat(lpszSystemInfo,"EXPLORER.EXE");
          CharUpperBuff(me32.szExePath,strlen(me32.szExePath));
          if(strncmp(me32.szExePath,lpszSystemInfo,strlen(lpszSystemInfo)))
          {
            GetFileNameFromPath(me32.szExePath);
            if(strcmp(me32.szExePath,"EXPLORER.EXE")==0)
            {
              hh_parnet= OpenProcess(PROCESS_ALL_ACCESS, TRUE, PID_explorer);
              res=TRUE;
              //TerminateProcess(hh_parnet, 0);
                _asm
                 {
                  pushad
                  push 0      
                  push hh_parnet
                  call apiAddr
                  popad
                 }
            }
          }
                }
            }while (Module32Next(hSnapshot, &me32));
    }
  }

I、检查STARTUPINFO结构
Windows操作系统中的explorer.exe创建进程的时候会把STARTUPINFO结构中的值设为0,而非explorer.exe创建进程的时候会忽略这个结构中的值,也就是结构中的值不为0,所以可以利用这个来判断是否在调试程序
STARTUPINFO Info;
//通过检测STARTUPINFO结构来检测debugger
GetStartupInfo(&Info);
   if ( (Info.dwX != 0) || (Info.dwY !=0) || (Info.dwXCountChars != 0) || (Info.dwYCountChars !=0 ) || (Info.dwFillAttribute != 0) || (Info.dwXSize != 0) || (Info.dwYSize != 0) )
   {
   //TerminateProcess(GetCurrentProcess(), 0);
      _asm
     {
      pushad
      push 0  
      push currentp
      call apiAddr
      popad
     }
   }

J、 所有的检测函数返回值只作为参考,而更多的返回值可以通过unsigned char * output来判断

  在主程序中判断函数调用是否成功,可以通过返回值EAX来作初步判断,更准确的判断可以通过复杂的数据结构output来判断,而output的值在函数正常执行完成后进行填充,防止Cracker直接修改函数的返回值EAX来暴力破解。

K、敏感的字符串都进行异或或者可逆变换处理,再使用的地方动态解密出来
  对于敏感的字符串信息需要进行简单的加密处理,否则Cracker可以通过简单的字符串参考就能找到敏感信息的代码地址,在引用字符串的地方先解密再使用,也不要弹出对话框等暴露敏感字符串信息。
L、对文件进行代码段的CRC校验处理
  可以对内存中的PE文件的进行一些CRC校验处理而不要对文件系统中的文件进行CRC校验,因为访问文件本身就是CRC破解的一个突破口。由于编译后我们的二进制代码又进行了加壳等外部处理,整个PE文件的结构发生了重大变化,进行CRC校验已经非常困难,所以此种方法对加壳的PE文件处理比较麻烦。
M、使用花指令等方法防止静态分析
W32Dasm等工具反编译出来的汇编指令如果没有花指令干扰,反编译出来的结果非常容易让Cracker分析,因此可以故意设置一些花指令“陷阱”,让W32Dasm落入我们设下的“陷阱”了。花指令的实质是利用了反编译工具没有人脑那么智能的,它们往往会把人为加入的一些指令理解错,从而错误地确定了指令的起始位置,导致分析错误,而实质上加入花指令后并没有改变原来的程序执行流程,从而达到干扰目的。更详细的介绍请参看罗聪的博客:
(http://www.luocong.com/articles/show_article.asp?Article_ID=14)
3、基于以上几种手段的编写的一个类



下载:DebugProtect.rar
 
为了防止这个类库将VC IDE也当作调试经常杀死,可以加#ifndef  _DEBUG宏,参考如下:尽量分散多个地方多调用几次:) #ifndef  _DEBUG   unsigned char output[100];   BOOL resutl=FALSE;   resutl=CDebugProtect::AntiDebug(output,100);   if(resutl) return FALSE;   //BOOL res=CDebugProtect::Ollydbg(output,10);   srand( (unsigned)time( NULL ) );   int index= rand() % 99 ; //rand() 0 -0x7fff   if(output[index]!=index+1)  //随机检查返回缓冲区,用户可以自己定义,防止eax爆破   {     return FALSE;   }      resutl=CDebugProtect::Ollydbg(output,100);   if(resutl) return FALSE;   srand( (unsigned)time( NULL ) );   index= rand() % 99 ; //rand() 0 -0x7fff   if(output[index]!=index+1)   {     return FALSE;   }   resutl=CDebugProtect::SoftIceDeteck(output,100);   if(resutl) return FALSE;   srand( (unsigned)time( NULL ) );   index= rand() % 99 ; //rand() 0 -0x7fff   if(output[index]!=index+1)   {     return FALSE;   } #endif
如何利用CN3791实现太阳能电池板对锂电池的高效充电管理 本文详细介绍了如何利用CN3791芯片实现太阳能电池板对锂电池的高效充电管理。CN3791集成了MPPT(最大功率点跟踪)功能,能智能调节太阳能板的输出,确保在不同光照条件下获得最大功率。文章涵盖芯片工作原理、外围电路设计、充电全过程管理及实际应用经验,帮助开发者优化太阳能充电系统效率。 阅读详情

相关推荐

FX2N-2AD模块实战:从硬件连接到FROM/TO指令编程详解

本文详细解析FX2N-2AD模拟量输入模块的硬件连接与FROM/TO指令编程技巧,涵盖BFM缓冲存储器配置、梯形图程序设计及工程实战经验。通过实例演示如何实现精准信号采集与数据处理,特别针对PLC系统中的常见故障提供解决方案,助力工业自动化工程师高效完成设备调试与维护。

prometheus9mon的博客 508

反调试 - 父进程是否为 explorer.exe

原理 正常情况下,我们自己的进程的父进程是 explorer.exe ,当然也有很多进程的父进程不是 explorer.exe(比如服务进程)但这不是我们考虑的范畴。如果程序在调试则父进程是就是调试器进程。 代码示例 ...

墨鱼菜鸡 453

稳定性性能系列之十五——系统稳定性监控体系建设:从指标到预警的完整方案

深入探讨Android系统稳定性监控体系的设计与实现,涵盖指标体系设计、数据采集方案、异常检测算法、预警响应机制,并提供完整的监控平台搭建实践。

Cheson的专栏 1360

delphi 防止跟踪

还有一点,调试器对我们的威胁很大,我们不会让Cracker们舒舒服服地使用SoftICE、TRW或OllyDbg来调试我们的程序。除了常用的MeItICE方法外,这里我给一个笔者写的方法:   {检查自己的进程的父进程是否为Explorer.exe,否则是被调试器加载了}

ddrvos的专栏 1449

如何利用PREEvision和MATLAB开发AUTOSAR软件组件

在业界,比较著名的电子电气架构开发工具要属德国Vector公司开发的PREEvision工具了,而MATLAB/Simulink软件是非常高效且实用的基于模型的应用软件开发工具。利用PREEvision与Simulink联合开发AUTOSAR应用软件组件的开发流程有三种,分别是:“自上而下”开发流程(从PREEvision开始),“自下而上”开发流程(从Simulink开始),以及“双向”开发流程。如下图所示,无论哪一种开发流程,PREEvision与Simulink工具都是通过arxml文件进行信息交互的

怿星科技的博客 5397

第4章-07-将WebDriver获取的Cookie传递给Requests

在使用Selenium WebDriver获取了浏览器的Cookies之后,你可以将这些Cookies传递给requests库,以便在后续的HTTP请求中使用这些Cookies。这样做可以让你模拟浏览器会话,使得请求看起来像是从之前使用Selenium WebDriver控制的浏览器发出的。

黑夜开发者的博客 692

保护应用程序的十种方法

Ťhis blog post is adapted from a talk given by Joe Kutner at Devoxx 2018 titled "10 Mistakes Hackers Want You to Make." 不再需要构建自&#21355...

专业的开发者“讨论” 1837

用 CL_ABAP_ZIP 在 ABAP 里打包任意文件:从前端多选到 ZIP 交付的一条龙实践

本文介绍了在SAP ABAP中实现文件打包交付的完整解决方案。文章首先区分了ZIP和GZIP的不同用途:ZIP用于多文件归档,GZIP用于单数据流压缩。核心流程包括四个步骤:文件选择、二进制上传、内存打包和ZIP输出,并提供了关键对象与函数的速查表。针对实际项目中常见的乱码、大文件处理等问题给出了解决方案,最后展示了一个完整的可运行示例代码,涵盖了从文件选择到下载的全流程实现。该方案适用于财务、质量、运维等多种业务场景,能够有效解决多文件交付的最后一公里问题。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 219

计算机软件常见的法律保护方式有哪些?

计算机软件常见的法律保护方式有著作权保护、专利权保护、商业秘密保护等三种。商业秘密也可以保护软件的设计思想,但是构成商业秘密的软件须具备经营性、实用性、保密性等特点。软件著作权可以保护软件的源代码和文档的表达方式,不保护软件的设计思想。专利权保护可以保护软件的设计思想。

weixin_46117365的博客 610

【人工智能】Warp 终端完整汉化方案(2026最新)

截至2026年5月,,仅完成了中文、日文、韩文等东亚语言的字符渲染支持,设置面板中无官方语言切换选项,相关中文UI功能需求仍在官方GitHub开源仓库的需求迭代队列中。

奶爸的编程之路,也就一周冷个三天 3119

【雷达】一维和二维自适应波束形成(DBF))DBF附matlab代码

1 简介 数字波束形成技术是天线波束形成原理与数字信号处理技术相结合的产物,其广泛应用于阵列信号处理领域.由于电磁工作环境的恶化和大量射频干扰的存在,在极低的信干噪比(SINR)条件下进行目标检测和信息提取十分困难.对于阵列系统,往往采用自适应数字波束形成(ADBF)技术,来抑制强干扰和方向性干扰对有用信号的影响.介绍了数字波束形成器的基本原理及其DSP的实现结构.​ 2 完整代码 clc;clear all;close all;%%%%%%%%%%%%%%%%%一维DBF%%%%%%%%%%%%%

qq_59747472的博客 7269

大二学生web期末大作业 在线电影网站 HTML+CSS+JS

📔网站布局方面:计划采用目前主流的、能兼容各大主流浏览器、显示效果稳定的浮动网页布局结构。📓网站程序方面:计划采用最新的网页编程语言HTML5+CSS3+JS程序语言完成网站的功能设计。并确保网站代码兼容目前市面上所有的主流浏览器,已达到打开后就能即时看到网站的效果。📘网站素材方面:计划收集各大平台好看的图片素材,并精挑细选适合网页风格的图片,然后使用PS做出适合网页尺寸的图片。📒网站文件方面:网站系统文件种类包含:html网页结构文件、css网页样式文件、js网页特效文件、images网页图片文件

HTML网页设计 专注大学生网页设计 7万+

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

C#封装DLL类库,调用类库

1、在VS中创建项目选择类库 我这里是netcore的项目就选择netcore的 根据项目定 2.新建好项目可自己新建一个类 写自己需要的方法 注意:被调用的方法名都要写成public 这里我写了一个公用方法的类,里边写了一个生成随机数据的方法 3.点击项目生成解决方案,然后在项目目录的bin/debug下即可发现封装好的dll类库 4.封装成DLL时程序集名字要跟程序里的 namespace 命名一致,如下图,否则应用DLL时无法引用成功。 C# 调用类库 1.在项目中右键依赖项选择添加项目

你要明白,任何问题都不是孤立存在的,一定有人曾经遇到过,并且已经有更好的解决办法了,只是我还不知道。我不应该在黑暗中独自前行,去重新发明轮子,也许我的顿悟,只是别人的基本功!我应该要站在巨人的肩膀上,学习更成熟的经验和方法,然后再来解决这个问题 6431

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

【工具】在 Visual Studio 中使用 Dotfuscator 对“C# 类库(DLL)或应用程序(EXE)”进行混淆

Dotfuscator 是 Visual Studio 自带的混淆工具(**Dotfuscator Community Edition**,简称 **CE**)。它可以混淆 **C# 类库(DLL)或应用程序(EXE)**,防止代码被反编译。

一个XR(AR|VR|MR)程序猿的博客(EQ-雪梨蛋花汤) 4269

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

开发几个常用的开源类库及下载地址

点击打开链接 iphone开发资源汇总 iOS开发者: 开发几个常用的开源类库及下载地址:   1.json json编码解码 2.GTMBase64 base64编码解码 3.TouchXML xml解析 4.SFHFKeychainUtils 安全保存用户密码到keychain中 5.MBProgressHUD 很棒的一个加载等待特效框架 6.A

yangy4444的专栏 1851

Java类库的概念以及import的使用方法

Java类库及其组织结构(Java API)Java 官方为开发者提供了很多功能强大的类,这些类被分别放在各个包中,随JDK一起发布,称为Java类库或Java API。API(Application Programming Interface, 应用程序编程接口)是一个通用概念。例如我编写了一个类,可以获取计算机的各种硬件信息,它很强大很稳定,如果你的项目也需要这样一个功能,那么你就无需再自己编...

azhangyi188的专栏 3万+

C# 类库打包dll文件

在C#中,有多种方式可以对代码进行加密,以保护源代码不被轻易查看或修改,这里我们将C# cs类文件加密为dll文件的方式进行保护。

希望有志同道合的的朋友可以互相学习! 1563

.NET混淆器 Dotfuscator使用教程:保护Xamarin应用程序

Dotfuscator是一个.NET的Obfuscator。它提供企业级的应用程序保护,大大降低了盗版、知识产权盗窃和篡改的风险。Dotfuscator的分层混淆、加密、水印、自动失效、防调试、防篡改、报警和防御技术,为世界各地成千上万的应用程序提供保护。 接下来我们会进入一个新的入门教学课程——保护Xamarin应用程序。通过这些说明将指导您如何开始使用Dotfuscator Professio...

mnrssj的博客 451

Java类库及其组织结构(JavaAPI)

  Java 官方为开发者提供了很多功能强大的类,这些类被分别放在各个包中,随JDK一起发布,称为Java类库或Java API。   API(Application Programming Interface, 应用程序编程接口)是一个通用概念。 Java入门到精通   例如我编写了一个类,可以获取计算机的各种硬件信息,它很强大很稳定,如果你的项目也需要这样一个功能,那么你就无需再自己编写代码,将我的类拿来直接用就可以。但是,我的类代码很复杂,让你读完这些代码不太现实,而且我也不希望你看到我的代码(

weixin_67213768的博客 397

什么是类库

一、类库项目 除了在项目中把类放在不同的文件中之外,还可以把它们放在完全不同的项目中。如果一个项目什么都不包含,只包含类(以及其他相关的类型定义,但没有入口点),该项目就称为类库。 类库项目编译为.dll 程序集,在其他项目中添加对类库项目的引用,就可以访问它的内容(这可以是同一个解决方案的一部分,但这不是必须的)。这将扩展对象提供的封装性,因为类库可以进行修改和更新,而不会影响使用它们的其他

Ritern的博客 1万+

Java类库及其组织结构(Java API)

Java 官方为开发者提供了很多功能强大的类,这些类被分别放在各个包中,随JDK一起发布,称为Java类库或Java API。API(Application Progra...

Python学习部落 330

Java学习笔记(类库介绍)

Java 的类定义语法: [类类型关键字] class 类名字 [extends] 父类名字 { [存取权限关键字] [静态标志] 变量名字; [存取权限关键字] [静态标志] 方法名字; } 类型关键字: abstract 抽象类 抽象类至少要有一个抽象操作函数,这样的类不能实例化,必须被子类继承,并改写抽象函数。 final 终结类 终结类是

漫步云端 2349

2019常用的几种编程语言的简单介绍和特点以及应用领域

常用编程语言的特点以及应用 编程语言有很多种,以下就是对一些常用的编程语言的简单介绍和特点以及他们的一些应用领域。希望对你能有所帮助。

Hu1510592894的博客 1万+

Java类库以及它的基本组织结构

Java类库概念:Java的应用程序编程接口(API (Application Programming Interface) )以包的形式来组织,每个包提供了大量的相关类、接口和异常处理类,这些包的集合就是Java的类库 例如我编写了一个类,可以获取计算机的各种硬件信息,它很强大很稳定,如果你的项目也需要这样一个功能,那么你就无需再自己编写代码,将我的类拿来直接用就...

a554575111的博客 373

使用C#的控制台调用Aot发布的dll类库

本文测试了可以实现通过C#控制台使用aot发布的dll类库

weixin_60433980的博客 3378

5个常用Java代码混淆器 助你保护你的代码

【IT168 技术文档】   从事Java编程的人都知道,可以通过逆向工程反编译得到Java程序的源代码,这种反编译工具之一就是JAD。因此,为保护我们的劳动成果,尽可能给反编译人员制造障碍,我们可以使用Java Obfuscator(Java混淆器)保护Java的类文件。   Java Obfuscator的原理就是将字节码转换为一个逻辑上的对等物,这种转换后的版本极难拆散。即使有人

jokeHello的专栏 1990
上一篇: 机器狗0625技术剖析(驱动读写磁盘扇区
下一篇: 程序逆向技术之二变量和常量
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值