windows下的反调试探究——调用API

NtGlobalFlag

在 32 位机器上,NtGlobalFlag字段位于PEB0x68的偏移处,64 位机器则是在偏移0xBC位置,该字段的默认值为 0。当调试器正在运行时,该字段会被设置为一个特定的值

该字段包含有一系列的标志位,由调试器创建的进程会设置以下标志位:

这里NtGlobalFlag的汇编代码如下,如果返回值为0x70则程序处于调试状态

那么可以用代码进行判断如下,若返回为TRUE则处于调试状态,若返回FALSE则未处于调试状态

这里直接用编译器打开,处于调试状态

正常打开则处于未调试状态

IsDebuggerPresent

IsDebuggerPresent这个API位于kernel32.dll里面,首先通过0x18偏移找到TEB,再通过0x30找到PEB

然后在PEB的0x2偏移找到BeingDebugged,这个值用来存储是否处于调试状态,PEB结构如下

0:023> dt ntdll!_PEB
   +0x000 InheritedAddressSpace : UChar
   +0x001 ReadImageFileExecOptions : UChar
   +0x002 BeingDebugged    : UChar
   +0x003 BitField         : UChar
   +0x003 ImageUsesLargePages : Pos 0, 1 Bit
   +0x003 IsProtectedProcess : Pos 1, 1 Bit
   +0x003 IsImageDynamicallyRelocated : Pos 2, 1 Bit
   +0x003 SkipPatchingUser32Forwarders : Pos 3, 1 Bit
   +0x003 IsPackagedProcess : Pos 4, 1 Bit
   +0x003 IsAppContainer   : Pos 5, 1 Bit
   +0x003 IsProtectedProcessLight : Pos 6, 1 Bit
   +0x003 IsLongPathAwareProcess : Pos 7, 1 Bit
   +0x004 Padding0         : [4] UChar
   +0x008 Mutant           : Ptr64 Void
   +0x010 ImageBaseAddress : Ptr64 Void
   +0x018 Ldr              : Ptr64 _PEB_LDR_DATA
   +0x020 ProcessParameters : Ptr64 _RTL_USER_PROCESS_PARAMETERS
   +0x028 SubSystemData    : Ptr64 Void
   +0x030 ProcessHeap      : Ptr64 Void
   +0x038 FastPebLock      : Ptr64 _RTL_CRITICAL_SECTION
   +0x040 AtlThunkSListPtr : Ptr64 _SLIST_HEADER
   +0x048 IFEOKey          : Ptr64 Void
   +0x050 CrossProcessFlags : Uint4B
   +0x050 ProcessInJob     : Pos 0, 1 Bit
   +0x050 ProcessInitializing : Pos 1, 1 Bit
   +0x050 ProcessUsingVEH  : Pos 2, 1 Bit
   +0x050 ProcessUsingVCH  : Pos 3, 1 Bit
   +0x050 ProcessUsingFTH  : Pos 4, 1 Bit
   +0x050 ProcessPreviouslyThrottled : Pos 5, 1 Bit
   +0x050 ProcessCurrentlyThrottled : Pos 6, 1 Bit
   +0x050 ProcessImagesHotPatched : Pos 7, 1 Bit
   +0x050 ReservedBits0    : Pos 8, 24 Bits
   +0x054 Padding1         : [4] UChar
   +0x058 KernelCallbackTable : Ptr64 Void
   +0x058 UserSharedInfoPtr : Ptr64 Void
   +0x060 SystemReserved   : Uint4B
   +0x064 AtlThunkSListPtr32 : Uint4B
   +0x068 ApiSetMap        : Ptr64 Void
   +0x070 TlsExpansionCounter : Uint4B
   +0x074 Padding2         : [4] UChar
   +0x078 TlsBitmap        : Ptr64 Void
   +0x080 TlsBitmapBits    : [2] Uint4B
   +0x088 ReadOnlySharedMemoryBase : Ptr64 Void
   +0x090 SharedData       : Ptr64 Void
   +0x098 ReadOnlyStaticServerData : Ptr64 Ptr64 Void
   +0x0a0 AnsiCodePageData : Ptr64 Void
   +0x0a8 OemCodePageData  : Ptr64 Void
   +0x0b0 UnicodeCaseTableData : Ptr64 Void
   +0x0b8 NumberOfProcessors : Uint4B
   +0x0bc NtGlobalFlag     : Uint4B
   +0x0c0 CriticalSectionTimeout : _LARGE_INTEGER
   +0x0c8 HeapSegmentReserve : Uint8B
   +0x0d0 HeapSegmentCommit : Uint8B
   +0x0d8 HeapDeCommitTotalFreeThreshold : Uint8B
   +0x0e0 HeapDeCommitFreeBlockThreshold : Uint8B
   +0x0e8 NumberOfHeaps    : Uint4B
   +0x0ec MaximumNumberOfHeaps : Uint4B
   +0x0f0 ProcessHeaps     : Ptr64 Ptr64 Void
   +0x0f8 GdiSharedHandleTable : Ptr64 Void
   +0x100 ProcessStarterHelper : Ptr64 Void
   +0x108 GdiDCAttributeList : Uint4B
   +0x10c Padding3         : [4] UChar
   +0x110 LoaderLock       : Ptr64 _RTL_CRITICAL_SECTION
   +0x118 OSMajorVersion   : Uint4B
   +0x11c OSMinorVersion   : Uint4B
   +0x120 OSBuildNumber    : Uint2B
   +0x122 OSCSDVersion     : Uint2B
   +0x124 OSPlatformId     : Uint4B
   +0x128 ImageSubsystem   : Uint4B
   +0x12c ImageSubsystemMajorVersion : Uint4B
   +0x130 ImageSubsystemMinorVersion : Uint4B
   +0x134 Padding4         : [4] UChar
   +0x138 ActiveProcessAffinityMask : Uint8B
   +0x140 GdiHandleBuffer  : [60] Uint4B
   +0x230 PostProcessInitRoutine : Ptr64     void 
   +0x238 TlsExpansionBitmap : Ptr64 Void
   +0x240 TlsExpansionBitmapBits : [32] Uint4B
   +0x2c0 SessionId        : Uint4B
   +0x2c4 Padding5         : [4] UChar
   +0x2c8 AppCompatFlags   : _ULARGE_INTEGER
   +0x2d0 AppCompatFlagsUser : _ULARGE_INTEGER
   +0x2d8 pShimData        : Ptr64 Void
   +0x2e0 AppCompatInfo    : Ptr64 Void
   +0x2e8 CSDVersion       : _UNICODE_STRING
   +0x2f8 ActivationContextData : Ptr64 _ACTIVATION_CONTEXT_DATA
   +0x300 ProcessAssemblyStorageMap : Ptr64 _ASSEMBLY_STORAGE_MAP
   +0x308 SystemDefaultActivationContextData : Ptr64 _ACTIVATION_CONTEXT_DATA
   +0x310 SystemAssemblyStorageMap : Ptr64 _ASSEMBLY_STORAGE_MAP
   +0x318 MinimumStackCommit : Uint8B
   +0x320 SparePointers    : [4] Ptr64 Void
   +0x340 SpareUlongs      : [5] Uint4B
   +0x358 WerRegistrationData : Ptr64 Void
   +0x360 WerShipAssertPtr : Ptr64 Void
   +0x368 pUnused          : Ptr64 Void
   +0x370 pImageHeaderHash : Ptr64 Void
   +0x378 TracingFlags     : Uint4B
   +0x378 HeapTracingEnabled : Pos 0, 1 Bit
   +0x378 CritSecTracingEnabled : Pos 1, 1 Bit
   +0x378 LibLoaderTracingEnabled : Pos 2, 1 Bit
   +0x378 SpareTracingBits : Pos 3, 29 Bits
   +0x37c Padding6         : [4] UChar
   +0x380 CsrServerReadOnlySharedMemoryBase : Uint8B
   +0x388 TppWorkerpListLock : Uint8B
   +0x390 TppWorkerpList   : _LIST_ENTRY
   +0x3a0 WaitOnAddressHashTable : [128] Ptr64 Void
   +0x7a0 TelemetryCoverageHeader : Ptr64 Void
   +0x7a8 CloudFileFlags   : Uint4B
   +0x7ac CloudFileDiagFlags : Uint4B
   +0x7b0 PlaceholderCompatibilityMode : Char
   +0x7b1 PlaceholderCompatibilityModeReserved : [7] Char
   +0x7b8 LeapSecondData   : Ptr64 _LEAP_SECOND_DATA
   +0x7c0 LeapSecondFlags  : Uint4B
   +0x7c0 SixtySecondEnabled : Pos 0, 1 Bit
   +0x7c0 Reserved         : Pos 1, 31 Bits
   +0x7c4 NtGlobalFlag2    : Uint4B

这里如果用vc6的话会提示没有这个API

需要自己定义这个API

直接运行处于调试状态

直接运行则不会显示处于调试状态

NtQueryInformationProcess

NtQueryInformationProcess 是微软未公开的一个API,目前只能够通过一些结构的名字和逆向的方式来推断用途

// NtQueryInformationProcess 函数原型
__kernel_entry NTSTATUS NtQueryInformationProcess(
  IN HANDLE           ProcessHandle,    // 进程句柄
  IN PROCESSINFOCLASS ProcessInformationClass,  // 检索的进程信息类型
  OUT PVOID           ProcessInformation,   // 接收进程信息的缓冲区指针
  IN ULONG            ProcessInformationLength,  // 缓冲区指针大小
  OUT PULONG          ReturnLength     // 实际接收的进程信息大小
);

// PROCESSINFOCLASS 结构体原型
typedef enum _PROCESSINFOCLASS
{
    ProcessBasicInformation,      // 0x0
    ProcessQuotaLimits, 
    ProcessIoCounters, 
    ProcessVmCounters, 
    ProcessTimes, 
    ProcessBasePriority, 
    ProcessRaisePriority,
    ProcessDebugPort,       // 0x7
    ProcessExceptionPort, 
    ProcessAccessToken, 
    ProcessLdtInformation, 
    ProcessLdtSize, 
    ProcessDefaultHardErrorMode, 
    ProcessIoPortHandlers, 
    ProcessPooledUsageAndLimits, 
    ProcessWorkingSetWatch,
    ProcessUserModeIOPL,
    ProcessEnableAlignmentFaultFixup, 
    ProcessPriorityClass, 
    ProcessWx86Information,
    ProcessHandleCount, 
    ProcessAffinityMask, 
    ProcessPriorityBoost, 
    ProcessDeviceMap, 
    ProcessSessionInformation, 
    ProcessForegroundInformation,
    ProcessWow64Information,      // 0x1A
    ProcessImageFileName,       // 0x1B
    ProcessLUIDDeviceMapsEnabled, 
    ProcessBreakOnTermination, 
    ProcessDebugObjectHandle,     // 0x1E
    ProcessDebugFlags,        // 0x1F
    ProcessHandleTracing, 
    ProcessIoPriority, 
    ProcessExecuteFlags, 
    ProcessResourceManagement, 
    ProcessCookie, 
    ProcessImageInformation, 
    ProcessCycleTime, 
    ProcessPagePriority, 
    ProcessInstrumentationCallback, 
    ProcessThreadStackAllocation, 
    ProcessWorkingSetWatchEx,
    ProcessImageFileNameWin32, 
    ProcessImageFileMapping, 
    ProcessAffinityUpdateMode, 
    ProcessMemoryAllocationMode, 
    ProcessGroupInformation,
    ProcessTokenVirtualizationEnabled, 
    ProcessConsoleHostProcess, 
    ProcessWindowInformation, 
    ProcessHandleInformation,
    ProcessMitigationPolicy,
    ProcessDynamicFunctionTableInformation,
    ProcessHandleCheckingMode,
    ProcessKeepAliveCount,
    ProcessRevokeFileHandles,
    ProcessWorkingSetControl,
    ProcessHandleTable, 
    ProcessCheckStackExtentsMode,
    ProcessCommandLineInformation,
    ProcessProtectionInformation,
    ProcessMemoryExhaustion,
    ProcessFaultInformation, 
    ProcessTelemetryIdInformation, 
    ProcessCommitReleaseInformation, 
    ProcessDefaultCpuSetsInformation,
    ProcessAllowedCpuSetsInformation,
    ProcessSubsystemProcess,
    ProcessJobMemoryInformation, 
    ProcessInPrivate, 
    ProcessRaiseUMExceptionOnInvalidHandleClose, 
    ProcessIumChallengeResponse,
    ProcessChildProcessInformation, 
    ProcessHighGraphicsPriorityInformation,
    ProcessSubsystemInformation, 
    ProcessEnergyValues, 
    ProcessActivityThrottleState, 
    ProcessActivityThrottlePolicy,
    ProcessWin32kSyscallFilterInformation,
    ProcessDisableSystemAllowedCpuSets, 
    ProcessWakeInformation,
    ProcessEnergyTrackingState,
    ProcessManageWritesToExecutableMemory,REDSTONE3
    ProcessCaptureTrustletLiveDump,
    ProcessTelemetryCoverage,
    ProcessEnclaveInformation,
    ProcessEnableReadWriteVmLogging, 
    ProcessUptimeInformation,
    ProcessImageSection,
    ProcessDebugAuthInformation, 
    ProcessSystemResourceManagement,
    ProcessSequenceNumber,
    ProcessLoaderDetour,
    ProcessSecurityDomainInformation, 
    ProcessCombineSecurityDomainsInformation, 
    ProcessEnableLogging, 
    ProcessLeapSecondInformation,
    ProcessFiberShadowStackAllocation,
    ProcessFreeFiberShadowStackAllocation,
    MaxProcessInfoClass
} PROCESSINFOCLASS;

ProcessDebugPort

未公开的ntdllNtQueryInformationProcess()函数接受一个信息类的参数用于查询。ProcessDebugPort(7)是其中的一个信息类,kernel32CheckRemoteDebuggerPresent()函数内部通过调用NtQueryInformationProcess()来检测调试,而NtQueryInformationProcess内部则是查询EPROCESS结构体的DebugPort字段,当进程正在被调试时,返回值为0xffffffff,实现代码如下

typedef NTSTATUS(NTAPI* pfnNtQueryInformationProcess)(
 _In_      HANDLE           ProcessHandle,
 _In_      UINT             ProcessInformationClass,
 _Out_     PVOID            ProcessInformation,
 _In_      ULONG            ProcessInformationLength,
 _Out_opt_ PULONG           ReturnLength
 );

bool NtQuery()
{
 pfnNtQueryInformationProcess NtQueryInformationProcess = NULL; // 存放 ntdll 中 NtQueryInformationProcess 函数地址
 NTSTATUS status;            // NTSTATUS 错误代码,0:执行成功
 DWORD isDebuggerPresent = -1;         // 如果当前被调试,则 = ffffffff
 HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));    // ntdll 模块句柄

 if (hNtDll)
 {
  // 取 NtQueryInformationProcess 函数地址
  NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformationProcess");

  // 取地址成功
  if (NtQueryInformationProcess)
  {
   // NtQueryInformationProcess 检测调试器
   status = NtQueryInformationProcess(GetCurrentProcess(), ProcessDebugPort, &isDebuggerPresent, sizeof(DWORD), NULL);

   // NtQueryInformationProcess 执行成功
   if (status == 0 && isDebuggerPresent != 0)
   {
    // 输出
    printf("status = %d\n", status);
    printf("isDebuggerPresent = %x\n", isDebuggerPresent);
    printf("当前处于调试状态\n");

    getchar();
    return 0;
   }
  }
 }

 // 输出
 printf("status = %d\n", status);
 printf("isDebuggerPresent = %x\n", isDebuggerPresent);
 printf("当前未处于调试状态\n");
}

isDebuggerPresent的值为-1的时候处于调试状态

为0的时候则为正常启动

ProcessDebugObjectHandle

ProcessDebugObjectHandle位于0x1E偏移,当status不为0、isDebuggerPresent不等于0时则处于调试状态

status = NtQueryInformationProcess(GetCurrentProcess(), 0x1E, &isDebuggerPresent, sizeof(DWORD), NULL);

ProcessDebugFlags

ProcessDebugFlags (0x1f)类返回EPROCESS结构体的NoDebugInherit的相反数,当调试器存在时,返回值为0,不存在时则返回1

status = NtQueryInformationProcess(GetCurrentProcess(), 0x1F, &isDebuggerPresent, sizeof(DWORD), NULL);

if (status == 0 && isDebuggerPresent == 0)

父进程

我们一般正常模式启动程序其父进程一般都是explorer.exe(不考虑服务进程),而当我们处于调试状态则父进程为调试器进程,那么我们就可以通过ntdll.dll里面的NtQueryInformationProcess来进行判断,实现代码如下

bool CheckParentProcess()
{
 pfnNtQueryInformationProcess NtQueryInformationProcess = NULL; // 存放 ntdll 中 NtQueryInformationProcess 函数地址
 HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));    // ntdll 模块句柄

 if (hNtDll)
 {
        struct PROCESS_BASIC_INFORMATION {
            ULONG ExitStatus; // 进程返回码
            PPEB PebBaseAddress; // PEB地址
            ULONG AffinityMask; // CPU亲和性掩码
            LONG BasePriority; // 基本优先级
            ULONG UniqueProcessId; // 本进程PID
            ULONG InheritedFromUniqueProcessId; // 父进程PID
        }ProcInfo;

        NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformationProcess");

        NtQueryInformationProcess(
            GetCurrentProcess(),
            ProcessBasicInformation, // 需要查询进程的基本信息
            &ProcInfo,
            sizeof(ProcInfo),
            NULL);

        DWORD ExplorerPID = 0;
        DWORD CurrentPID = ProcInfo.InheritedFromUniqueProcessId;
        GetWindowThreadProcessId(FindWindow(L"DebugPrint", NULL), &ExplorerPID);
        return ExplorerPID == CurrentPID ? false : true;
 }

}

实现效果如下

KernelDebuggerEnabled

NtQuerySystemInformation 被 ntdll.dll 导出,当第一个参数传入 0x23 (SystemInterruptInformation) 时,会返回一个 SYSTEM_KERNEL_DEBUGGER_INFORMATION 结构,里面的成员KdKdDebuggerEnable 和 KdDebuggerNotPresent 标志系统是否启用内核调试

typedef struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION {
    BOOLEAN KernelDebuggerEnabled;
    BOOLEAN KernelDebuggerNotPresent;
} SYSTEM_KERNEL_DEBUGGER_INFORMATION, * PSYSTEM_KERNEL_DEBUGGER_INFORMATION;
typedef NTSTATUS(WINAPI* pNtQuerySystemInformation)(IN UINT SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength);


bool CheckSystemKernelDebuggerInformation()
{
    pNtQuerySystemInformation NtQuerySystemInformation = NULL; // 存放 ntdll 中 NtQueryInformationProcess 函数地址
 HMODULE hNtDll = LoadLibrary(TEXT("ntdll.dll"));    // ntdll 模块句柄

 if (hNtDll)
 {
        NtQuerySystemInformation = (pNtQuerySystemInformation)GetProcAddress(hNtDll, "NtQuerySystemInformation");

        struct _SYSTEM_KERNEL_DEBUGGER_INFORMATION {
            BOOLEAN KernelDebuggerEnabled;
            BOOLEAN KernelDebuggerNotPresent;
        }DebuggerInfo = { 0 };

        NtQuerySystemInformation(
            (SYSTEM_INFORMATION_CLASS)0x23, // 查询信息类型
            &DebuggerInfo, // 输出查询信息
            sizeof(DebuggerInfo), // 查询类型大小
            NULL); // 实际返回大小

        // 通过是否开启内核调试器知道当前系统有没有被调试
        return DebuggerInfo.KernelDebuggerEnabled;
 }

因为这里检测的是否启用内核调试,这里直接运行是不处于调试状态

使用调试模式启动win10运行则显示处于调试状态

ThreadHideFromDebugger

通过ZwSetInformationThread函数,设置 ThreadHideFromDebugger 此参数将使这条线程对调试器隐藏,即调试器收不到调试信息

typedef enum THREAD_INFO_CLASS {
ThreadHideFromDebugger = 17
};

typedef NTSTATUS(NTAPI* ZW_SET_INFORMATION_THREAD)(
    IN HANDLE ThreadHandle,
    IN THREAD_INFO_CLASS ThreadInformaitonClass,
    IN PVOID ThreadInformation,
    IN ULONG ThreadInformationLength);

void ZSIT_DetachDebug()
{
    ZW_SET_INFORMATION_THREAD ZwSetInformationThread;

    ZwSetInformationThread = (ZW_SET_INFORMATION_THREAD)GetProcAddress(LoadLibrary(L"ntdll.dll"), "ZwSetInformationThread");

    ZwSetInformationThread(GetCurrentThread(), ThreadHideFromDebugger, NULL, NULL);
}

这里调用函数之后为了证明程序运行成功,这里加上一行输出语句

然后尝试使用od附加,这里可以看到是没有DebugPrint.exe这个进程的

那么这里为了更明显一点,首先看下QQ的PID是3872对应十六进制为F20是能够对应上的

然后计算DebugPrint.exe的十六进制为5D8,在进程里面是看不到的

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(学习日记)2024.03.02:UCOSIII第四节:创建任务

写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈。 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录&a…

【MySQL 系列】在 Windows 上安装 MySQL

在 Windows 平台上安装 MySQL 很简单,并不需要太复杂的步骤。按照本文的步骤操练起来就可以了。 文章目录 1、下载 MySQL 安装程序2、安装 MySQL 数据库2.1、选择安装类型2.2、检查所需组件2.3、安装所选产品组件2.4、产品配置2.5、配置高可用性2.6、配置服务器类型…

UDP协议和TCP协议详解

文章目录 应用层自定义协议 传输层udp协议TCP协议1.确认应答2.超时重传3.连接管理建立连接, 三次握手断开连接, 四次挥手tcp的状态 4.滑动窗口5.流量控制6.拥塞控制7.延时应答8.携带应答9.面向字节流10.异常情况 应用层 自定义协议 客户端和服务器之间往往要进行交互的是“结构…

网络工程师笔记8

华为VRP系统 设备管理方式 web管理方式 命令行管理方式 修改命令:undo 基础配置命令

学习python时一些笔记

1、winr 命令提示符的快捷键 输入cmd进入终端 2、在终端运行桌面上的python文件 cd desktop(桌面) cd是进入该文件夹的意思。 cd .. 回到上一级 运行python时一定要找到文件的所在地 输入python进入,exit()退出%s字符串占位符%d数字占位符%f浮点数占位符input输…

【Python】变量的引用

🚩 WRITE IN FRONT 🚩 🔎 介绍:"謓泽"正在路上朝着"攻城狮"方向"前进四" 🔎🏅 荣誉:2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…

KMP算法和Manacher算法

KMP算法 KMP算法解决的问题 KMP算法用来解决字符串匹配问题: 找到长串中短串出现的位置. KMP算法思路 暴力比较与KMP的区别 暴力匹配: 对长串的每个位,都从头开始匹配短串的所有位. KMP算法: 将短字符串前后相同的部分存储在 n e x t next next数组里,让之前匹配过的信息指…

如何利用pynlpir进行中文分词并保留段落信息

一、引言 nlpir是由张华平博士开发的中文自然处理工具,可以对中文文本进行分词、聚类分析等,它既有在线的中文数据大数据语义智能分析平台,也有相关的python包pynlpir,其github的地址是: Pynlpir在Github上的地址 这…

算法(6)——模拟

一、什么是模拟 模拟是对真实事物或者过程的虚拟。在编程时为了实现某个功能,可以用语言来模拟那个功能,模拟成功也就相应地表示编程成功。 二、模拟算法的思路 模拟算法是一种基本的算法思想,可用于考查程序员的基本编程能力,…

抖店入驻费用是多少?新手入驻都有哪些要求?2024费用明细!

我是电商珠珠 我做电商做了将近五年,做抖店做了三年多,期间还带着学员一起做店。 今天,就来给大家详细的讲一下在抖音开店,需要多少费用,最低需要投入多少。 1、营业执照200元左右 就拿个体店举例,在入…

二叉搜索树题目:将有序数组转换为二叉搜索树

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法思路和算法证明代码复杂度分析 题目 标题和出处 标题:将有序数组转换为二叉搜索树 出处:108. 将有序数组转换为二叉搜索树 难度 4 级 题目描述 要求 给定整数数组 nums \texttt{nums}…

大辩论:人工智能时代人类和软件的未来

关于人工智能将在多大程度上接管软件开发、交付和支持任务及其对就业的影响,聆听双方的争论,对于技术来说既令人兴奋,又让人类感到恐惧。争论是这样的: 人工智能倡导者:欢迎来到未来!凭借当今人工智能的能…

猫挑食不吃猫粮怎么办?可以解决猫咪挑食的主食冻干推荐

现在的猫奴们普遍将自家的小猫视为掌上明珠,宠爱有加。然而,这种宠爱有时也会导致猫咪养成一些不良习惯,比如挑食。猫挑食不吃猫粮怎么办?今天为大家分享一个既不让咱宝贝猫咪受罪又可以改善猫咪挑食的方法。 一、猫咪是为什么挑食…

(C语言)qsort函数详解

目录 1. qsort解释 2. qsort实例 2.1 qsort排列整形数组类型: 2.2 qsort排列结构体类型数据(字符串): 2.3 qsort排列结构体类型数据(整形): 1. qsort解释 我们可以进入网站:qso…

第一天 走进Docker的世界

第一天 走进Docker的世界 介绍docker的前世今生,了解docker的实现原理,以Django项目为例,带大家如何编写最佳的Dockerfile构建镜像。通过本章的学习,大家会知道docker的概念及基本操作,并学会构建自己的业务镜像&…

王者荣耀整蛊搭建直播新玩法/obs贴纸配置教程

最近很火的王者荣耀整蛊直播,相信很多玩王者的玩家也想开一个直播,但是看到这种直播娱乐效果很有意思也想搭建一个,这里梦哥给大家出了一期搭建的教程! 进阶版视频教程: 这期的教程是进阶版新玩法升级,具体…

DataGrip 2023:让数据库开发变得更简单、更高效 mac/win

JetBrains DataGrip 2023是一款功能强大的数据库IDE,专为数据库开发和管理而设计。通过DataGrip,您可以连接到各种关系型数据库管理系统(RDBMS),并使用其提供的一组工具来查询、管理、编辑和开发数据库。 DataGrip 2023软件获取 DataGrip 2…

前端面试 跨域理解

2 实现 2-1 JSONP 实现 2-2 nginx 配置 2-2 vue 开发中 webpack自带跨域 2 -3 下载CORS 插件 或 chrome浏览器配置跨域 2-4 通过iframe 如:aaa.com 中读取bbb.com的localStorage 1)在aaa.com的页面中,在页面中嵌入一个src为bbb.com的iframe&#x…

大模型理论基础(so-large-lm)课程笔记!

Datawhale干货 作者:辣条,Datawhale优秀学习者 前 言 在当前信息时代,大型语言模型(Large Language Models,LLMs)的发展速度和影响力日益显著。随着技术进步,我们见证了从基本的Transformer架构…
最新文章