c++ - 动态载入DLL接口,可以给IDA静态分析增加一点麻烦

news2025/4/26 19:01:00

文章目录

    • c++ - 动态载入DLL接口,可以给IDA静态分析增加一点麻烦
    • 概述
    • 笔记
    • 测试工程
    • test_load_dll_then_call_api.cpp
    • CMyUser32Dll.h
    • CMyUser32Dll.cpp
    • LateLoad.h
    • IDA静态分析
    • 引入表中没有PostMessageW
    • 字符串查找能找到PostMessageW
    • 备注
    • 看看CMyUser32Dll.h编译完的样子
    • 备注 - debug版不生成调试信息
    • debug版即使不生成调试信息,也可能带入一些和工程目录相关的字符串
    • 解决方法1
    • 解决方法2
    • 备注
    • END

c++ - 动态载入DLL接口,可以给IDA静态分析增加一点麻烦

概述

工程中用到了PostMessage来压入任务,太扎眼了。在IDA静态分析时,看API引用,很容易看到压入任务的实现。
想动态载入API, 看看静态分析效果如何?

笔记

网上有大神开源了一个动态载入DLL的封装类(http://www.codeproject.com/KB/DLL/LateLoad.aspx)

以前也用过,只是用来方便动态调用DLL接口。
这次用,主要是看看用IDA静态分析时,动态载入的API接口是否容易识别?

测试工程

写个demo(vs2019 vc++ console), 转圈打印字符串. 如果圈数>10, 向控制台程序的窗口post消息,关闭控制台程序的窗口,从而达到关闭控制台程序的目的。
在这里插入图片描述

test_load_dll_then_call_api.cpp

//! \file test_load_dll_then_call_api.cpp

#include <windows.h>
#include <stdlib.h>
#include <stdio.h>

#include "CMyUser32Dll.h"

int main()
{
	int i = 0;
	CMyUser32Dll myUser32Dll;

	do {
		Sleep(500);
		printf("[%d] runing\n", ++i);

		if (i > 10)
		{
			// 发送消息,关掉控制台程序的窗口
			myUser32Dll.PostMessageW(GetConsoleWindow(), WM_CLOSE, 0, 0);
		}
	} while (true);

	return EXIT_SUCCESS;
}

CMyUser32Dll.h

//! \file CMyLoadDll.h

#ifndef __C_MY_LOAD_DLL_H__
#define __C_MY_LOAD_DLL_H__

#include "LateLoad.h"

// User32.dll
// https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-postmessagea?redirectedfrom=MSDN&devlangs=cpp&f1url=%3FappId%3DDev16IDEF1%26l%3DZH-CN%26k%3Dk(WINUSER%252FPostMessage)%3Bk(PostMessage)%3Bk(DevLang-C%252B%252B)%3Bk(TargetOS-Windows)%26rd%3Dtrue
/*
BOOL PostMessageA(
  [in, optional] HWND   hWnd,
  [in]           UINT   Msg,
  [in]           WPARAM wParam,
  [in]           LPARAM lParam
);
*/
// https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-postmessagew
/*
BOOL PostMessageW(
  [in, optional] HWND   hWnd,
  [in]           UINT   Msg,
  [in]           WPARAM wParam,
  [in]           LPARAM lParam
);
*/

LATELOAD_BEGIN_CLASS(CMyUser32Dll, TEXT("User32.dll"), FALSE, FALSE)
LATELOAD_FUNC_4(FALSE, BOOL, STDAPICALLTYPE, PostMessageW, HWND, UINT, WPARAM, LPARAM)
LATELOAD_END_CLASS()

#endif // #ifndef __C_MY_LOAD_DLL_H__

CMyUser32Dll.cpp

//! \file CMyLoadDll.cpp

#include "pch.h"
// #include "memOpt/my_debug_new_define.h"

#include "CMyUser32Dll.h"


LateLoad.h

#ifndef __LATE_LOAD__H__
#define __LATE_LOAD__H__

#if _MSC_VER > 1000
#pragma once
#endif

#include <Windows.h>
#include <assert.h>

/*
	Module : LateLoad.h
	Purpose: I was tired of constantly re-writing LoadLibrary & GetProcAddress code, 
	         over & over & over again.  So I created a series of macros that will 
	         define & create a wrapper class to do it all for me.
	         This is NOT an end-all-be-all solution for loading DLLs.  This is just a
	         handy lightweight helper when you would use LoadLibrary/GetProcAddress.
	         For more information on DLLs, check out MSDN.

	         This was inspired by my own need, as well as a nice little MSDN article 
	         titled "DLLs the Dynamic Way" by "MicHael Galkovsky"
	         http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/dlldynamic.asp
	         Unfortunatly, there was no source to go with the article. So, I wrote this 
	         version quite a bit differently.

	Author : Copyright (c) 2004 by Jason De Arte, All Rights Reserved.
	Site   : http://1001010.com/code/	         
	
	License: Use it however you like as a compiled portion of your product(s).  
	         Don't be a jerk by claiming the it as your own.

	Usage  : The following will declare the class "CUser32Wrapper" that will load
	         function pointer(s) from USER32.DLL.  Those function names will become 
	         member function(s) of the newly created class.

	LATELOAD_BEGIN_CLASS(CUser32Wrapper,user32,FALSE)
		LATELOAD_FUNC_0(NULL,HCURSOR,WINAPI,GetCursor)
		LATELOAD_FUNC_1(NULL,HANDLE,WINAPI,NonExistantFunction,BOOL)
	LATELOAD_END_CLASS()

	// The above statements will auto-generate a class that functionaly equivalent to...
	class CUser32Wrapper : public CLateLoadBase
	{
	public:
		BOOL Is_GetCursor();
		HCURSOR WINAPI GetCursor();
		BOOL Is_NonExistantFunction();
		HANDLE WINAPI NonExistantFunction();
	};

	// And usage is even easier
	CUser32Wrapper uw;
	HCURSOR h = uw.GetCursor();

	// And for DLLs missing a function export, you can still use the member function!
	uw.NonExistantFunction(true);
	// It will just return the default non-existant value in the definition
	
	// To determine if the funtion was imported, use the "BOOL Is_<FunctionName>();" member
	Is_NonExistantFunction();
	// If it exists, it will return TRUE.  False if it does not exist

	-------------------------------------------

	Let's look at the various defines that are used...

	LATELOAD_BEGIN_CLASS(CUser32Wrapper,user32,FALSE)
	 CUser32Wrapper - the class that will be created
	 user32 - the library that will be loaded 
	 FALSE - determines if "FreeLibrary()" will be called in the destructor.


	LATELOAD_FUNC_0(NULL,HCURSOR,WINAPI,GetCursor)
	 NULL - if the ProcAddress was not loaded, this value is returned in the call to that func
	 HCURSOR - the return type for the function
	 WINAPI - function calling convention
	 GetCursor - the exported function

	LATELOAD_FUNC_1 (up to _9)
	 Identical to LATELOAD_FUNC_0, except it allows 1-9 parameters to the function
	
	LATELOAD_FUNC_0_ (up to _9)
	 Same as before, but for use with NULL return types

	LATELOAD_END_CLASS()
	 finalizes the class declaration

	-------------------------------------------
	History:
		2004.Feb.29.JED - Created
*/

//
// Used for keeping track
//
enum ImportedProcState
{
	ipsUnknown = 0,  // No attempts to load the Proc have been made yet
	ipsMissing,      // GetProcAddress failed to find the exported function
	ipsAvailable,    // the Proc is Ready & Available for use
	ips_MAX
};

#ifndef NO_VTABLE
# if _MSC_VER > 1000
#  define NO_VTABLE __declspec(novtable)
# else
// 2004.Feb.29.JED - Note to self, find out what is appropriate under non-msvc compilers
//#  define NO_VTABLE
# endif //_MSC_VER
#endif

//
// Declaration for the utility base class, not intended for non-inherited use.
//
class NO_VTABLE CLateLoadBase
{
	//
	// Why no v-table?
	// 1) not needed
	// 2) reduces code size
	// 3) LATELOAD_BEGIN_CLASS calls ZeroMemory to blank out all the derived function 
	//    pointers & ImportedProcState memeber variables - in the process the vtable
	//    will get blanked out.
	// 4) This class is not intended to be instantiated on its own.
	// 5) Makes it so that using this class on its own will cause an Access Violation
	//
protected:
	HMODULE  m_module;          // Handle to the DLL
	DWORD    m_dwLoadLibError;  // If there was an error from LoadLibrary
	BOOL     m_bManaged;        // FreeLibrary in the destructor?
	LPTSTR   m_pszModule;       // The name of the module, handy for first-use loading

	/*****************************************************************************
	* NAME: 
	*  CLateLoadBase::dll_LoadLibrary
	* 
	* DESCRIPTION: 
	*  Loads the dll.  
	* 
	*******************************************************************************/
protected:
	BOOL dll_LoadLibrary(LPCTSTR pszLibrary, BOOL bDoItNow)
	{
		//
		// Make a record of the DLL name
		//
		if( !m_pszModule )
		{
			if( pszLibrary && *pszLibrary)
			{
				int nLen = lstrlen(pszLibrary); 
				m_pszModule = new TCHAR[nLen+2]; 
				if( m_pszModule ) 
				{ 
					ZeroMemory( m_pszModule, sizeof(TCHAR)*(nLen+2) ); 
					lstrcpy(m_pszModule,pszLibrary); 
				} 
				else 
				{ 
					assert(!"CLateLoadBase::dll_LoadLibrary - Unable to allocate memory for a string!"); 
				}
			} 
			else 
			{ 
				assert(!"CLateLoadBase::dll_LoadLibrary - We need a valid pszLibrary string"); 
			} 
		}

		// Nothing to do?
		if( m_module )
			return TRUE;

		// Should we do this later?
		if( !bDoItNow )
			return FALSE;

		// Load the DLL
		m_dwLoadLibError = 0;
		m_module = ::LoadLibrary(pszLibrary);
		if( m_module )
			return TRUE;

		// Unable to load it, find out why
		m_dwLoadLibError = GetLastError();

		// We rely on the last error being not equal to zero on LoadLibrary failure.
		// So, in the off chance it IS zero, we set it to a non-zero value.  
		// Tip: According to MSDN, Bit 29 in Get/SetLastError logic is reserved for Application 
		//      defined error codes.  No system level error codes should have this bit set.
		if( !m_dwLoadLibError )
		{
			assert(!"Wow, that should NOT have happened!  Could you tell JED how you did it?");
			m_dwLoadLibError = 0x20000000;
		}

		return FALSE;
	}

	/*****************************************************************************
	* NAME: 
	*  CLateLoadBase::dll_GetProcAddress
	* 
	* DESCRIPTION: 
	*  Loads the function pointer from the DLL
	* 
	*******************************************************************************/
protected:
	FARPROC dll_GetProcAddress(LPCSTR pszFunctionName, ImportedProcState& ips)
	{
		FARPROC pfn = NULL;
		ips = ipsUnknown;
		
		// Does the DLL still need to be loaded?
		if( !m_module && m_pszModule && *m_pszModule && 
		    0 == m_dwLoadLibError   // There is no reason to attempt to load the DLL more than once
		  )
		{
			dll_LoadLibrary(m_pszModule,TRUE);
		}

		if( m_module )
		{		
			pfn = ::GetProcAddress(m_module,pszFunctionName);
			if( pfn )
				ips = ipsAvailable;
			else
				ips = ipsMissing;
		}

		return pfn; 
	}


	/*****************************************************************************
	* NAME: 
	*  CLateLoadBase::~CLateLoadBase
	* 
	* DESCRIPTION: 
	*  Description goes here...
	* 
	*******************************************************************************/
public:
	~CLateLoadBase()
	{
		if( m_bManaged && m_module )
			::FreeLibrary(m_module);
		m_module  = NULL;
		m_bManaged = FALSE;
		if( m_pszModule )
			delete m_pszModule;
		m_pszModule = NULL;
	}

	/*****************************************************************************
	* NAME: 
	*  CLateLoadBase::dll_GetLoadError
	* 
	* DESCRIPTION: 
	*  If LoadLibrary failed, returns the error code.
	*  If there was no error, returns zero
	* 
	*******************************************************************************/
public:
	DWORD dll_GetLoadError()  
	{
		return m_dwLoadLibError;     
	}

	/*****************************************************************************
	* NAME: 
	*  CLateLoadBase::dll_IsLoaded
	* 
	* DESCRIPTION: 
	*  Is the DLL loaded?
	* 
	*******************************************************************************/
public:
	BOOL dll_IsLoaded()      
	{ 
		return NULL!=m_module;       
	}

	/*****************************************************************************
	* NAME: 
	*  CLateLoadBase::dll_GetModuleName
	* 
	* DESCRIPTION: 
	*  return the name of the module loaded
	* 
	*******************************************************************************/
public:
	LPCTSTR dll_GetModuleName() 
	{ 
		return (LPCTSTR)m_pszModule; 
	}
};


//--------------------------------------------------------------------------------------
//
// Start of macros
//
//--------------------------------------------------------------------------------------


//
// Start, Declares the name of the class
//
// ClassName   = the name of the class
// ModuleName  = the DLL name
// bLoadDllNow = if true, the DLL will be loaded in the constructor.  
//               if false, it will ONLY be loaded when any bound function is first used
// bManaged    = if true, FreeLibrary will be called in the destructor
//
#define LATELOAD_BEGIN_CLASS(ClassName,ModuleName,bLoadDllNow,bManaged) \
class ClassName : public CLateLoadBase \
{ \
public:\
	ClassName()\
	{\
		/*Automagicaly blank out all the function pointers and ImportedProcState member vars*/ \
		/*that will be declared in following LATELOAD_FUNC_* declarations, very handy. */ \
		ZeroMemory(static_cast<ClassName*>(this),sizeof(ClassName)); \
		m_bManaged = bManaged; \
		/*and load the DLL*/ \
		dll_LoadLibrary(ModuleName,bLoadDllNow); \
	}


//
// Function Declaration, Zero Parameters, returns a value 
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType,  type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
//
// A function prototype that looked like...
//   typedef BOOL (CALLBACK* SOMETHING)();
//  or
//   BOOL CALLBACK Something();
//
// Would be changed to...
//   LATELOAD_FUNC_0(0,BOOL,CALLBACK,Something)
//
// If "Something" could not be loaded, and it was called - it would return 0
//
#define LATELOAD_FUNC_0(ErrorResult,ReturnType,CallingConv,FuncName) \
protected: \
	typedef ReturnType(CallingConv * TYPE_##FuncName)(); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	ReturnType FuncName() \
	{\
		if( !Is_##FuncName() ) \
			return ErrorResult; \
		return m_pf##FuncName(); \
	}


//
// Function Declaration, One Parameter, returns a value 
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType,  type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
// A function prototype that looked like...
//   typedef BOOL (CALLBACK* SOMETHING)(BOOL);
//  or
//   BOOL CALLBACK Something(BOOL bEnable);
//
// Would be changed to...
//   LATELOAD_FUNC_1(0,BOOL,CALLBACK,Something,BOOL)
//
// If "Something" could not be loaded, and it was called - it would return 0
//
#define LATELOAD_FUNC_1(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1) \
protected: \
	typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	ReturnType FuncName(ParamType1 p1) \
	{\
		if( !Is_##FuncName() ) \
			return ErrorResult; \
		return m_pf##FuncName(p1); \
	}


//
// Function Declaration, Two Parameters, returns a value 
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType,  type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
// A function prototype that looked like...
//   typedef BOOL (CALLBACK* SOMETHING)(BOOL,INT);
//  or
//   BOOL CALLBACK Something(BOOL bEnable, INT nNum);
//
// Would be changed to...
//   LATELOAD_FUNC_2(0,BOOL,CALLBACK,Something,BOOL,INT)
//
// If "Something" could not be loaded, and it was called - it would return 0
//
#define LATELOAD_FUNC_2(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2) \
protected: \
	typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	ReturnType FuncName(ParamType1 p1,ParamType2 p2) \
	{\
		if( !Is_##FuncName() ) \
			return ErrorResult; \
		return m_pf##FuncName(p1,p2); \
	}


//
// Function Declaration, Three Parameters, returns a value 
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType,  type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_3(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3) \
protected: \
	typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3) \
	{\
		if( !Is_##FuncName() ) \
			return ErrorResult; \
		return m_pf##FuncName(p1,p2,p3); \
	}


//
// Function Declaration, Four Parameters, returns a value 
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType,  type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_4(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4) \
protected: \
	typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4) \
	{\
		if( !Is_##FuncName() ) \
			return ErrorResult; \
		return m_pf##FuncName(p1,p2,p3,p4); \
	}


//
// Function Declaration, Five Parameters, returns a value 
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType,  type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_5(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5) \
protected: \
	typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5) \
	{\
		if( !Is_##FuncName() ) \
			return ErrorResult; \
		return m_pf##FuncName(p1,p2,p3,p4,p5); \
	}


//
// Function Declaration, Six Parameters, returns a value 
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType,  type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_6(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6) \
protected: \
	typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6) \
	{\
		if( !Is_##FuncName() ) \
			return ErrorResult; \
		return m_pf##FuncName(p1,p2,p3,p4,p5,p6); \
	}


//
// Function Declaration, Seven Parameters, returns a value 
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType,  type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_7(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7) \
protected: \
	typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7) \
	{\
		if( !Is_##FuncName() ) \
			return ErrorResult; \
		return m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7); \
	}


//
// Function Declaration, Eight Parameters, returns a value 
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType,  type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_8(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8) \
protected: \
	typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8) \
	{\
		if( !Is_##FuncName() ) \
			return ErrorResult; \
		return m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8); \
	}


//
// Function Declaration, Nine Parameters, returns a value 
//
// ErrorResult, Default return value if the function could not be loaded & it is called anyways
// ReturnType,  type of value that the function returns
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_9(ErrorResult,ReturnType,CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9) \
protected: \
	typedef ReturnType(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	ReturnType FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8,ParamType9 p9) \
	{\
		if( !Is_##FuncName() ) \
			return ErrorResult; \
		return m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8,p9); \
	}


//
// Function Declaration, Zero Parameters, returns nothing 
//
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
//
// A function prototype that looked like...
//   typedef VOID (CALLBACK* SOMETHING)();
//  or
//   VOID CALLBACK Something();
//
// Would be changed to...
//   LATELOAD_FUNC_0_VOID(CALLBACK,Something)
//
#define LATELOAD_FUNC_0_VOID(CallingConv,FuncName) \
protected: \
	typedef void(CallingConv * TYPE_##FuncName)(); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	void FuncName() \
	{\
		if( Is_##FuncName() ) \
			m_pf##FuncName(); \
	}


//
// Function Declaration, One Parameters, returns nothing 
//
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
// A function prototype that looked like...
//   typedef VOID (CALLBACK* SOMETHING)(BOOL);
//  or
//   VOID CALLBACK Something(BOOL bEnable);
//
// Would be changed to...
//   LATELOAD_FUNC_1_VOID(CALLBACK,Something,BOOL)
//
#define LATELOAD_FUNC_1_VOID(CallingConv,FuncName,ParamType1) \
protected: \
	typedef void(CallingConv * TYPE_##FuncName)(ParamType1); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	void FuncName(ParamType1 p1) \
	{\
		if( Is_##FuncName() ) \
			m_pf##FuncName(p1); \
	}


//
// Function Declaration, Two Parameters, returns nothing 
//
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
// A function prototype that looked like...
//   typedef VOID (CALLBACK* SOMETHING)(BOOL,INT);
//  or
//   VOID CALLBACK Something(BOOL bEnable, INT nNumber);
//
// Would be changed to...
//   LATELOAD_FUNC_2_VOID(CALLBACK,Something,BOOL,INT)
//
#define LATELOAD_FUNC_2_VOID(CallingConv,FuncName,ParamType1,ParamType2) \
protected: \
	typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	void FuncName(ParamType1 p1,ParamType2 p2) \
	{\
		if( Is_##FuncName() ) \
			m_pf##FuncName(p1,p2); \
	}


//
// Function Declaration, Three Parameters, returns nothing 
//
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_3_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3) \
protected: \
	typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3) \
	{\
		if( Is_##FuncName() ) \
			m_pf##FuncName(p1,p2,p3); \
	}


//
// Function Declaration, Four Parameters, returns nothing 
//
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_4_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4) \
protected: \
	typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4) \
	{\
		if( Is_##FuncName() ) \
			m_pf##FuncName(p1,p2,p3,p4); \
	}


//
// Function Declaration, Five Parameters, returns nothing 
//
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_5_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5) \
protected: \
	typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5) \
	{\
		if( Is_##FuncName() ) \
			m_pf##FuncName(p1,p2,p3,p4,p5); \
	}


//
// Function Declaration, Six Parameters, returns nothing 
//
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_6_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6) \
protected: \
	typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6) \
	{\
		if( Is_##FuncName() ) \
			m_pf##FuncName(p1,p2,p3,p4,p5,p6); \
	}


//
// Function Declaration, Seven Parameters, returns nothing 
//
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_7_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7) \
protected: \
	typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7) \
	{\
		if( Is_##FuncName() ) \
			m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7); \
	}


//
// Function Declaration, Eight Parameters, returns nothing 
//
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_8_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8) \
protected: \
	typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8) \
	{\
		if( Is_##FuncName() ) \
			m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8); \
	}


//
// Function Declaration, Nine Parameters, returns nothing 
//
// CallingConv, Calling convention of the function
// FuncName,    Name of the function
// ParamN       types of the function parameters
//
#define LATELOAD_FUNC_9_VOID(CallingConv,FuncName,ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9) \
protected: \
	typedef void(CallingConv * TYPE_##FuncName)(ParamType1,ParamType2,ParamType3,ParamType4,ParamType5,ParamType6,ParamType7,ParamType8,ParamType9); \
	TYPE_##FuncName m_pf##FuncName; \
	ImportedProcState m_ips##FuncName;\
public: \
	BOOL Is_##FuncName() \
	{ \
		if(ipsUnknown == m_ips##FuncName) \
			m_pf##FuncName = (TYPE_##FuncName)dll_GetProcAddress(#FuncName, m_ips##FuncName); \
		return(ipsAvailable == m_ips##FuncName); \
	} \
	void FuncName(ParamType1 p1,ParamType2 p2,ParamType3 p3,ParamType4 p4,ParamType5 p5,ParamType6 p6,ParamType7 p7,ParamType8 p8,ParamType9) \
	{\
		if( Is_##FuncName() ) \
			m_pf##FuncName(p1,p2,p3,p4,p5,p6,p7,p8,p9); \
	}



//
// End of the class
//
#define LATELOAD_END_CLASS()  };


#endif //__LATE_LOAD__H__

IDA静态分析

引入表中没有PostMessageW

在这里插入图片描述

字符串查找能找到PostMessageW

在这里插入图片描述
在这里插入图片描述
可以顺着字符串,找到动态载入API的实现。
在这里插入图片描述
rcx是类指针this
[rcx + 0x18]就是保存PostMessageW函数地址的指针变量
在这里插入图片描述

在IDA中搜索文本18h, 就能找到动态调用postMessageW的调用点。
在这里插入图片描述
如果程序大了,想知道API的动态调用点,应该是挺不好找的。
如果将字符串编码后,需要用到的时候,再解码来用,那么调试者就只能动态调试才能找到思路了。
如果这样的话,唯一不能隐藏的就是LoadLibary和GetProcAddress。剩下2这个API无所谓,因为壳程序人家也是留下这2个API的,如果人家愿意调试你的程序,也挡不住人家。

备注

如果在程序中动态载入API, 可以给IDA静态分析增加一点麻烦。
虽然麻烦增加的不多,但是有点用。

看看CMyUser32Dll.h编译完的样子

CMyUser32Dll.h是包含在main.cpp中,进行宏展的。
编译main.cpp, 就能看到CMyUser32Dll.h中宏展开的样子。
在这里插入图片描述
在这里插入图片描述
整理 test_load_dll_then_call_api.i

// test_load_dll_then_call_api.cpp的宏展开的整理

enum ImportedProcState
{
	ipsUnknown = 0,  
	ipsMissing,      
	ipsAvailable,    
	ips_MAX
};

class __declspec(novtable) CLateLoadBase
{
protected:
	HMODULE  m_module;          
	DWORD    m_dwLoadLibError;  
	BOOL     m_bManaged;        
	LPTSTR   m_pszModule;       

protected:
	BOOL dll_LoadLibrary(LPCTSTR pszLibrary, BOOL bDoItNow)
	{
		if( !m_pszModule )
		{
			if( pszLibrary && *pszLibrary)
			{
				int nLen = lstrlenW(pszLibrary); 
				m_pszModule = new TCHAR[nLen+2]; 
				if( m_pszModule ) 
				{ 
					memset((m_pszModule),0,(sizeof(TCHAR)*(nLen+2))); 
					lstrcpyW(m_pszModule,pszLibrary); 
				} 
				else 
				{ 
					assert(false);
				}
			} 
			else 
			{ 
				assert(false);
			} 
		}
		
		if( m_module )
			return 1;
		
		if( !bDoItNow )
			return 0;
		
		m_dwLoadLibError = 0;
		m_module = ::LoadLibraryW(pszLibrary);
		if( m_module )
			return 1;
		
		m_dwLoadLibError = GetLastError();
		
		if( !m_dwLoadLibError )
		{
			assert(false);
			m_dwLoadLibError = 0x20000000;
		}

		return 0;
	}

protected:
	FARPROC dll_GetProcAddress(LPCSTR pszFunctionName, ImportedProcState& ips)
	{
		FARPROC pfn = 0;
		ips = ipsUnknown;
		
		
		if( !m_module && m_pszModule && *m_pszModule && 
		    0 == m_dwLoadLibError   
		  )
		{
			dll_LoadLibrary(m_pszModule,1);
		}

		if( m_module )
		{		
			pfn = ::GetProcAddress(m_module,pszFunctionName);
			if( pfn )
				ips = ipsAvailable;
			else
				ips = ipsMissing;
		}

		return pfn; 
	}
public:
	~CLateLoadBase()
	{
		if( m_bManaged && m_module )
			::FreeLibrary(m_module);
		m_module  = 0;
		m_bManaged = 0;
		if( m_pszModule )
			delete m_pszModule;
		m_pszModule = 0;
	}

public:
	DWORD dll_GetLoadError()  
	{
		return m_dwLoadLibError;     
	}

public:
	BOOL dll_IsLoaded()      
	{ 
		return 0!=m_module;       
	}

public:
	LPCTSTR dll_GetModuleName() 
	{ 
		return (LPCTSTR)m_pszModule; 
	}
};

class CMyUser32Dll : public CLateLoadBase 
{ 
public: 
	CMyUser32Dll() 
	{ 
		memset((static_cast<CMyUser32Dll*>(this)),0,(sizeof(CMyUser32Dll))); 
		m_bManaged = 0; 
		dll_LoadLibrary(L"User32.dll",0); 
	}

protected: 
	typedef BOOL(__stdcall * TYPE_PostMessageW)(HWND,UINT,WPARAM,LPARAM); 
	TYPE_PostMessageW m_pfPostMessageW; 
	ImportedProcState m_ipsPostMessageW;
public: 
	BOOL Is_PostMessageW()
	{ 
		if(ipsUnknown == m_ipsPostMessageW) 
			m_pfPostMessageW = (TYPE_PostMessageW)dll_GetProcAddress("PostMessageW", m_ipsPostMessageW); 
		
		return(ipsAvailable == m_ipsPostMessageW); 
	} 
	
	BOOL PostMessageW(HWND p1,UINT p2,WPARAM p3,LPARAM p4) 
	{ 
		if( !Is_PostMessageW() )
			return 0; 
		return m_pfPostMessageW(p1,p2,p3,p4); 
	}
};

int main()
{
	int i = 0;
	CMyUser32Dll myUser32Dll;

	do {
		Sleep(500);
		printf("[%d] runing\n", ++i);

		if (i > 10)
		{
			
			myUser32Dll.PostMessageW(GetConsoleWindow(), 0x0010, 0, 0);
		}
	} while (true);

	return 0;
}

备注 - debug版不生成调试信息

VS2019工程的debug版默认是生成.pdb的, 如果到了发行阶段,又不想生成release版(以前听说过,有的软件发行时,如果生成release版就会报错,厂家又解决不了,只能以debug版来发行),那么可以在编译选项中去掉调试信息,这样就不会生成pdb了。
在这里插入图片描述

debug版即使不生成调试信息,也可能带入一些和工程目录相关的字符串

在这里插入图片描述
这些和工程目录相关的字符串的引入,看IDA的字符串引用,是和debug版的new, assert等用到了__FILE__, __LINE__有关系。

解决方法1

将工程目录模拟成磁盘,在磁盘根目录下生成发布版(即使是debug), 这样,在工程中留下的字符串,就比较短。也不那么敏感。只和工程本身相关。如果在客户那里出了问题,就能看到断言,用户截个图就大概知道问题在哪里。
在这里插入图片描述

解决方法2

release版,但是不优化。
如果真的是程序有问题,只能在debug版下运行不报错,只要release版不优化,这样大概也是不会出问题的。
如果程序真的有问题,还是将bug从根上搞掉才是解决问题的态度。
在这里插入图片描述
在这里插入图片描述
release版默认虽然没有DEBUG预处理宏,但是还是会生成调试信息,所有也要去掉调试信息才靠谱。
在这里插入图片描述
在这里插入图片描述

看release版不优化(也不带调试信息)的EXE, 已经看不到和工程相关的路径和文件信息了。
看到有个和工程所在盘符相关的x:字符串,去看了一下,并没有引用关系。

备注

用动态载入DLL接口的方法,将IsDebuggerPresent动态来用,能隐蔽一些。

END

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

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

相关文章

Rust - 所有权

所有的程序都必须和计算机内存打交道&#xff0c;如何从内存中申请空间来存放程序的运行内容&#xff0c;如何在不需要的时候释放这些空间&#xff0c;成了重中之重&#xff0c;也是所有编程语言设计的难点之一。在计算机语言不断演变过程中&#xff0c;出现了三种流派&#xf…

【JS】数组交换位置

公式 arr.splice(oldIndex, delCount, ...arr.splice(newIndex, delCount, arr[oldIndex])) arr - 操作的数组delCount - 删除的数组个数oldIndex - 交换位置的数组下标1newIndex - 交换位置的数组下标2...arr - 提取数组里的元素 splice删除元素时&#xff0c;返回一个数组&a…

每日一题:缺失的第一个正数

给你一个未排序的整数数组 nums &#xff0c;请你找出其中没有出现的最小的正整数。 请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,0] 输出&#xff1a;3 解释&#xff1a;范围 [1,2] 中的数字都在数组…

实验笔记之——RGBD GS-ICP SLAM配置与测试

《RGBD GS-ICP SLAM》是最新开源的一个3DGS-SLAM工作&#xff0c;通过利用GICP来实现当前帧gaussian与已mapping的gaussian进行匹配进行位姿的估算&#xff0c;并通过关键帧的选择策略来进一步提升performance~ Use G-ICP to align the current frame with the 3D GS map whic…

计算机网络----第十二天

交换机端口安全技术和链路聚合技术 1、端口隔离技术&#xff1a; 用于在同vlan内部隔离用户&#xff1b; 同一隔离组端口不能通讯&#xff0c;不同隔离组端口可以通讯; 2、链路聚合技术&#xff1a; 含义&#xff1a;把连接到同一台交换机的多个物理端口捆绑为一个逻辑端口…

HLOOKUP函数结合数据验证实现的动态图表

小伙伴们&#xff0c;大家好啊&#xff01;今天我们分享一个使用HLOOKUP函数结合数据验证实现的动态图表技巧&#xff1b; 接下来我们具体说说操作步骤吧。 步骤1&#xff1a;选中A列的【路口车辆通过数】单元格区域&#xff0c;复制粘贴后到右边的空白区域&#xff0c;如I列…

【微服务】------架构设计及常用组件

前言 在当今迅猛发展的软件开发领域&#xff0c;微服务架构已经成为构建灵活、可扩展系统的关键方法之一。本文将带领读者深入了解微服务架构的核心思想&#xff0c;并介绍构建这一架构所需的常用组件&#xff0c;为各位开发者提供全面的指导和洞察力。 BigDiagram 我们从一…

HttpServletRequest/Response

HttpServletRequest 一些常用类的用法 package Demo;import javax.jws.WebService; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import ja…

改进YOLOv8系列:结合自研注意力模块MultiScaleAttentiveConv (MSAConv)

改进YOLOv8注意力系列七:结合空间关系增强注意力SGE、SKAttention动态尺度注意力、全局上下文信息注意力Triplet Attention 代码MultiScaleAttentiveConv (MSAConv)本文提供了改进 YOLOv8注意力系列包含不同的注意力机制以及多种加入方式,在本文中具有完整的代码和包含多种更…

计算机网络书籍--《网络是怎样连接的》阅读笔记

第一章 浏览器生成信息 1.1 生成HTTP请求信息 1.1.1 URL Uniform Resource Locator, 统一资源定位符。就是网址。 不同的URL能够用来判断使用哪种功能来访问相应的数据&#xff0c;比如访问Web服务器就要用”http:”&#xff0c;而访问FTP服务器用”ftp:”。 FTP&#xff…

笔记本台式机电脑 “睡眠和休眠”有什么区别,那个更省电

笔记本台式机电脑 Windows 系统里睡眠和休眠有什么区别&#xff0c;睡眠和休眠那个更省电&#xff0c;睡眠和休眠使用那个更好&#xff0c;当不用电脑时&#xff0c;通常有三种方式让电脑休息&#xff1a;关机、睡眠和休眠。关机的定义大家都懂&#xff0c;但睡眠和休眠就容易让…

基于Java的XxlCrawler网络信息爬取实战-以中国地震台网为例

目录 前言 一、信息网站介绍 1、网站介绍 2、 地震历史信息 3、 历史信息接口分析 二、XxlCrawler组件 1、关于XxlCrawler 2、核心概念介绍 三、实际信息爬取 1、新建maven项目 2、新建model层对象 3、实际爬取 总结 前言 如今&#xff0c;只要谈起网络信息爬取也就…

MathJax —— Vue3的使用方法

版本&#xff1a; mathjax3 需要实现效果 一、使用方式 1. index.html 中引入 <!-- 识别单行&#xff0c;行内&#xff0c;\( \)样式的公式 --><script>MathJax {tex: {inlineMath: [[$, $],[$$, $$], [\\(, \\)]]},};</script><script id"MathJ…

Pixel 手机上连接提示受阻,无法上网-解决方法

命令行中输入 adb shell settings delete global captive_portal_https_urladb shell settings delete global captive_portal_http_url输入服务器信息 adb shell settings put global captive_portal_http_url http://connect.rom.miui.com/generate_204adb shell settings …

Autosar Dcm配置-手动配置RID及Routine功能实现-基于ETAS软件

文章目录 前言Routine介绍Routine配置DcmDsdDcmDspDcmDspRoutinesSWC配置总结前言 之前介绍了DID的配置,本文介绍UDS诊断中,另外一种常用的功能Routine的配置,及生成代码的使用。 Routine介绍 Routine一般用于ECU较复杂的控制功能。使用UDS服务ID为0x31 31后面跟的是子服…

antd+vue——datepicker日期控件——禁用日期功能

需求&#xff1a;今天之前的日期禁用 <a-date-pickerv-model.trim"formNE.deliveryTime":disabled-date"disabledDate"valueFormat"YYYY-MM-DD"allowClearstyle"width: 100%" />禁用日期的范围&#xff1a; //时间范围 disab…

机器学习第34周周报VBAED

文章目录 week34 VBAED摘要Abstract一、文献阅读1. 题目2. abstract3. 网络架构3.1 序列问题阐述3.2 变分模态分解3.3 具有 BiLSTM 和双向输入注意力的编码器3.4 具有 BiLSTM 和双向时间注意力的解码器 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1 数据集数据预处…

ESP32系统监测(基于ESP-IDF)

主要参考资料&#xff1a; CSDN文章《ESP32 IDF开发调试奇技淫巧》: https://blog.csdn.net/qq_43332314/article/details/131859971 目录 查询系统剩余堆/最小堆大小查询线程剩余栈大小方法一方法二 查询CPU占用率 查询系统剩余堆/最小堆大小 查询系统剩余堆、最小堆大小的 A…

加速Python循环的12种方法,最高可以提速900倍

在本文中&#xff0c;我将介绍一些简单的方法&#xff0c;可以将Python for循环的速度提高1.3到900倍。 Python内建的一个常用功能是timeit模块。下面几节中我们将使用它来度量循环的当前性能和改进后的性能。 对于每种方法&#xff0c;我们通过运行测试来建立基线&#xff0…

redis的设计与实现(五)——独立功能

1. Redis的其他功能 redis 除了简单对对象的增删改查的功能之外&#xff0c;其实还有其他高级功能&#xff0c;了解这些内容有利于我们更灵活的使用 redis 完成我们的业务功能。 2. 发布与订阅 2.1. 基本概念 很多中间件都有发布与订阅功能&#xff0c;但是&#xff0c;作为一…