SEH学习

自己做了一个SEH相关的一个小程序,顺便在调试的时候观察一下

0:000> g $exentry
ModLoad: 75a90000 75ab5000   C:\Windows\SysWOW64\IMM32.DLL
eax=001bf840 ebx=00300000 ecx=00851010 edx=00851010 esi=00851010 edi=00851010
eip=00851010 esp=001bf7e8 ebp=001bf7f4 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
Project1!_Start:
00851010 6764a10000      mov     eax,dword ptr fs:[00000000h] fs:0053:00000000=001bf840
_Start:
    assume fs:nothing
	mov eax,fs:[0]         ;<---IP
    push offset myHandler
    push fs:[0]
    mov fs:[0],esp
    mov ecx,-1
    mov [eax],ecx
    xor eax,eax
    mov [eax],eax
    retn
END	_Start
_0:000> !exchain
001bf840: ntdll!_except_handler4+0 (775da040)
  CRT scope  0, filter: ntdll!__RtlUserThreadStart+3ad46 (7760293b)
                func:   ntdll!__RtlUserThreadStart+3addf (776029d4)
001bf858: ntdll!FinalExceptionHandlerPad54+0 (775e8ff6)
Invalid exception stack at ffffffff
_Start:
    assume fs:nothing
	mov eax,fs:[0]         
    push offset myHandler
    push fs:[0]
    mov fs:[0],esp        
    mov ecx,-1       ;<---IP
    mov [eax],ecx
    xor eax,eax
    mov [eax],eax
    retn
END	_Start
0:000> !exchain
001bf7e0: Project1!_Start+fffffffffffffff0 (00851000)
001bf840: ntdll!_except_handler4+0 (775da040)
  CRT scope  0, filter: ntdll!__RtlUserThreadStart+3ad46 (7760293b)
                func:   ntdll!__RtlUserThreadStart+3addf (776029d4)
001bf858: ntdll!FinalExceptionHandlerPad54+0 (775e8ff6)
Invalid exception stack at ffffffff

发现handler函数在0x00851000处,反汇编一下

0:000> u 00851000
Project1!_Start+0xffffffff`fffffff0 [D:\seh\Project1\KillSeh.asm @ 24]:
00851000 6a04            push    4
00851002 6a00            push    0
00851004 6803408500      push    offset Project1!messuc (00854003)
00851009 6a00            push    0
0085100b e82e000000      call    Project1!MessageBoxA (0085103e)
Project1!_Start [D:\seh\Project1\KillSeh.asm @ 34]:
00851010 6764a10000      mov     eax,dword ptr fs:[00000000h]
00851015 6800108500      push    offset Project1!_Start+0xffffffff`fffffff0 (00851000)
0085101a 6764ff360000    push    dword ptr fs:[0000h]

然后发现我这个程序没有返回,由于在汇编中我写在start前面,所以会错上加错,在ash链上的函数应该返回一个EXCEPTION_CONTINUE让程序继续搜索下一个异常处理程序(excep_handler4)
于是乎我定义了一下ExceptionContinueSearch = 1(估计库里面也有)

mov eax,ExceptionContinueSearch
retn

再继续调试,这次终于找到元凶了

ntdll!_except_handler4:
775da040 8bff            mov     edi,edi
775da042 55              push    ebp
775da043 8bec            mov     ebp,esp
775da045 ff7514          push    dword ptr [ebp+14h]
775da048 ff7510          push    dword ptr [ebp+10h]
775da04b ff750c          push    dword ptr [ebp+0Ch]
775da04e ff7508          push    dword ptr [ebp+8]
775da051 68603f5d77      push    offset ntdll!__security_check_cookie (775d3f60)
775da056 6860336877      push    offset ntdll!__security_cookie (77683360)
775da05b e870bcffff      call    ntdll!_except_handler4_common (775d5cd0)
775da060 83c418          add     esp,18h
775da063 5d              pop     ebp
775da064 c3              ret

又是security_check,这玩意一般是防止栈溢出用的,这里我也没调过,接着看下一个函数

ntdll!_except_handler4_common

发现了一个函数用来调用seh链上的异常处理函数

ntdll!ExecuteHandler2:
775e8e4c 55              push    ebp
775e8e4d 8bec            mov     ebp,esp
775e8e4f ff750c          push    dword ptr [ebp+0Ch]
775e8e52 52              push    edx          ;难道用栈改seh这么常见吗,分分钟被hook掉(bushi),有空可以试一试
775e8e53 64ff3500000000  push    dword ptr fs:[0]
775e8e5a 64892500000000  mov     dword ptr fs:[0],esp
775e8e61 ff7514          push    dword ptr [ebp+14h]
775e8e64 ff7510          push    dword ptr [ebp+10h]
775e8e67 ff750c          push    dword ptr [ebp+0Ch]
775e8e6a ff7508          push    dword ptr [ebp+8]
775e8e6d 8b4d18          mov     ecx,dword ptr [ebp+18h]
775e8e70 ffd1            call    ecx
775e8e72 648b2500000000  mov     esp,dword ptr fs:[0]
775e8e79 648f0500000000  pop     dword ptr fs:[0]
775e8e80 8be5            mov     esp,ebp
775e8e82 5d              pop     ebp
775e8e83 c21400          ret     14h

再上一级函数

;ntdll!RtlpExecuteHandlerForException
ntdll!ExecuteHandler:
775e8e20 53              push    ebx
775e8e21 56              push    esi
775e8e22 57              push    edi
775e8e23 33c0            xor     eax,eax
775e8e25 33db            xor     ebx,ebx
775e8e27 33f6            xor     esi,esi
775e8e29 33ff            xor     edi,edi
775e8e2b ff742420        push    dword ptr [esp+20h]
775e8e2f ff742420        push    dword ptr [esp+20h]
775e8e33 ff742420        push    dword ptr [esp+20h]
775e8e37 ff742420        push    dword ptr [esp+20h]
775e8e3b ff742420        push    dword ptr [esp+20h]
775e8e3f e808000000      call    ntdll!ExecuteHandler2 (775e8e4c)
775e8e44 5f              pop     edi
775e8e45 5e              pop     esi
775e8e46 5b              pop     ebx
775e8e47 c21400          ret     14h

再上一级

ntdll!RtlDispatchException:
775c80cc 8bff            mov     edi,edi
775c80ce 55              push    ebp
775c80cf 8bec            mov     ebp,esp
775c80d1 83e4f8          and     esp,0FFFFFFF8h
775c80d4 83ec7c          sub     esp,7Ch
775c80d7 a160336877      mov     eax,dword ptr [ntdll!__security_cookie (77683360)]
775c80dc 33c4            xor     eax,esp
775c80de 89442478        mov     dword ptr [esp+78h],eax
775c80e2 8b550c          mov     edx,dword ptr [ebp+0Ch]
775c80e5 53              push    ebx
775c80e6 56              push    esi
775c80e7 8b7508          mov     esi,dword ptr [ebp+8]
775c80ea 33db            xor     ebx,ebx
775c80ec 57              push    edi
775c80ed 89542410        mov     dword ptr [esp+10h],edx
775c80f1 885c240f        mov     byte ptr [esp+0Fh],bl
775c80f5 813e060000c0    cmp     dword ptr [esi],0C0000006h
775c80fb 7410            je      ntdll!RtlDispatchException+0x41 (775c810d)
775c80fd 8b4e0c          mov     ecx,dword ptr [esi+0Ch]
775c8100 e826030000      call    ntdll!RtlpIsUserCallTargetBitMapCheckFault (775c842b)
775c8105 84c0            test    al,al
775c8107 0f85f6a90300    jne     ntdll!RtlDispatchException+0x3aa37 (77602b03)
775c810d 64a130000000    mov     eax,dword ptr fs:[00000030h]
775c8113 f7406800008000  test    dword ptr [eax+68h],800000h
775c811a 0f8504aa0300    jne     ntdll!RtlDispatchException+0x3aa58 (77602b24)
775c8120 e80b65fcff      call    ntdll!LdrControlFlowGuardEnforced (7758e630)
775c8125 8b7c2410        mov     edi,dword ptr [esp+10h]
775c8129 85c0            test    eax,eax
775c812b 0f852c010000    jne     ntdll!RtlDispatchException+0x191 (775c825d)
775c8131 53              push    ebx
775c8132 8bd7            mov     edx,edi
775c8134 8bce            mov     ecx,esi
775c8136 e8463a0000      call    ntdll!RtlpCallVectoredHandlers (775cbb81)
775c813b 84c0            test    al,al
775c813d 0f85f2000000    jne     ntdll!RtlDispatchException+0x169 (775c8235)
775c8143 8d542420        lea     edx,[esp+20h]
775c8147 8d4c241c        lea     ecx,[esp+1Ch]
775c814b e8af020000      call    ntdll!RtlpGetStackLimits (775c83ff)
775c8150 648b3d00000000  mov     edi,dword ptr fs:[0]
775c8157 8d442418        lea     eax,[esp+18h]
775c815b 53              push    ebx
775c815c 6a04            push    4
775c815e 50              push    eax
775c815f 6a22            push    22h
775c8161 6aff            push    0FFFFFFFFh
775c8163 897c2428        mov     dword ptr [esp+28h],edi
775c8167 895c242c        mov     dword ptr [esp+2Ch],ebx
775c816b e8209e0000      call    ntdll!NtQueryInformationProcess (775d1f90)
775c8170 85c0            test    eax,eax
775c8172 0f88bda90300    js      ntdll!RtlDispatchException+0x3aa69 (77602b35)
775c8178 f644241840      test    byte ptr [esp+18h],40h
775c817d 7518            jne     ntdll!RtlDispatchException+0xcb (775c8197)
775c817f 8b54241c        mov     edx,dword ptr [esp+1Ch]
775c8183 51              push    ecx
775c8184 ff742424        push    dword ptr [esp+24h]
775c8188 8bcf            mov     ecx,edi
775c818a e805020000      call    ntdll!RtlpIsValidExceptionChain (775c8394)
775c818f 84c0            test    al,al
775c8191 0f84a7a90300    je      ntdll!RtlDispatchException+0x3aa72 (77602b3e)
775c8197 8b4c2414        mov     ecx,dword ptr [esp+14h]
775c819b 895c2424        mov     dword ptr [esp+24h],ebx
775c819f 83f9ff          cmp     ecx,0FFFFFFFFh
775c81a2 0f848f000000    je      ntdll!RtlDispatchException+0x16b (775c8237)
775c81a8 3b4c241c        cmp     ecx,dword ptr [esp+1Ch]
775c81ac 0f82eb000000    jb      ntdll!RtlDispatchException+0x1d1 (775c829d)
775c81b2 8d4108          lea     eax,[ecx+8]
775c81b5 3b442420        cmp     eax,dword ptr [esp+20h]
775c81b9 0f87de000000    ja      ntdll!RtlDispatchException+0x1d1 (775c829d)
775c81bf f6c103          test    cl,3
775c81c2 0f85d5000000    jne     ntdll!RtlDispatchException+0x1d1 (775c829d)
775c81c8 8b4904          mov     ecx,dword ptr [ecx+4]
775c81cb 3b4c2420        cmp     ecx,dword ptr [esp+20h]
775c81cf 0f82be000000    jb      ntdll!RtlDispatchException+0x1c7 (775c8293)
775c81d5 ff742410        push    dword ptr [esp+10h]
775c81d9 8b54241c        mov     edx,dword ptr [esp+1Ch]
775c81dd e8c1000000      call    ntdll!RtlIsValidHandler (775c82a3)
775c81e2 84c0            test    al,al
775c81e4 0f84b3000000    je      ntdll!RtlDispatchException+0x1d1 (775c829d)
775c81ea 8b7c2414        mov     edi,dword ptr [esp+14h]
775c81ee 895c2428        mov     dword ptr [esp+28h],ebx
775c81f2 385c240f        cmp     byte ptr [esp+0Fh],bl
775c81f6 0f8579a90300    jne     ntdll!RtlDispatchException+0x3aaa9 (77602b75)
775c81fc ff7704          push    dword ptr [edi+4]
775c81ff 8d442430        lea     eax,[esp+30h]
775c8203 50              push    eax
775c8204 ff742418        push    dword ptr [esp+18h]
775c8208 57              push    edi
775c8209 56              push    esi
;################################################################
775c820a e8010c0200      call    ntdll!RtlpExecuteHandlerForException (775e8e10)
;##########################目前ip在此#############################
775c820f 8b4c2428        mov     ecx,dword ptr [esp+28h]
775c8213 85c9            test    ecx,ecx
775c8215 0f8572a90300    jne     ntdll!RtlDispatchException+0x3aac1 (77602b8d)
775c821b 8b542424        mov     edx,dword ptr [esp+24h]
775c821f 3bd7            cmp     edx,edi
775c8221 0f8471a90300    je      ntdll!RtlDispatchException+0x3aacc (77602b98)
775c8227 2bc3            sub     eax,ebx
775c8229 754a            jne     ntdll!RtlDispatchException+0x1a9 (775c8275)
775c822b 40              inc     eax
775c822c 844604          test    byte ptr [esi+4],al
775c822f 0f85b9a90300    jne     ntdll!RtlDispatchException+0x3ab22 (77602bee)
775c8235 b301            mov     bl,1
775c8237 8b542410        mov     edx,dword ptr [esp+10h]
775c823b 8bce            mov     ecx,esi
775c823d 6a01            push    1
775c823f e83d390000      call    ntdll!RtlpCallVectoredHandlers (775cbb81)
;下次有空看看这个函数
775c8244 8ac3            mov     al,bl
775c8246 8b8c2484000000  mov     ecx,dword ptr [esp+84h]
775c824d 5f              pop     edi
775c824e 5e              pop     esi
775c824f 5b              pop     ebx
775c8250 33cc            xor     ecx,esp
775c8252 e809bd0000      call    ntdll!__security_check_cookie (775d3f60)
775c8257 8be5            mov     esp,ebp
775c8259 5d              pop     ebp
775c825a c20800          ret     8

再上一级

ntdll!KiUserExceptionDispatcher:
775d42b0 833d4ce9677700  cmp     dword ptr [ntdll!LdrDelegatedKiUserExceptionDispatcher (7767e94c)],0
775d42b7 740e            je      ntdll!KiUserExceptionDispatcher+0x17 (775d42c7)
775d42b9 8b0d4ce96777    mov     ecx,dword ptr [ntdll!LdrDelegatedKiUserExceptionDispatcher (7767e94c)]
775d42bf ff15e0116877    call    dword ptr [ntdll!__guard_check_icall_fptr (776811e0)]
775d42c5 ffe1            jmp     ecx
775d42c7 fc              cld
775d42c8 8b4c2404        mov     ecx,dword ptr [esp+4]
775d42cc 8b1c24          mov     ebx,dword ptr [esp]
775d42cf 51              push    ecx
775d42d0 53              push    ebx
;###############################################################################
775d42d1 e8f63dffff      call    ntdll!RtlDispatchException (775c80cc)
;##########################目前ip在此############################################
775d42d6 0ac0            or      al,al
775d42d8 740c            je      ntdll!KiUserExceptionDispatcher+0x36 (775d42e6)
775d42da 5b              pop     ebx
775d42db 59              pop     ecx
775d42dc 6a00            push    0
775d42de 51              push    ecx
775d42df e86cdfffff      call    ntdll!NtContinue (775d2250)
775d42e4 eb0b            jmp     ntdll!KiUserExceptionDispatcher+0x41 (775d42f1)
775d42e6 5b              pop     ebx
775d42e7 59              pop     ecx
775d42e8 6a00            push    0
775d42ea 51              push    ecx
775d42eb 53              push    ebx
775d42ec e82ff1ffff      call    ntdll!NtRaiseException (775d3420)
775d42f1 83c4ec          add     esp,0FFFFFFECh
775d42f4 890424          mov     dword ptr [esp],eax
775d42f7 c744240401000000 mov     dword ptr [esp+4],1
775d42ff 895c2408        mov     dword ptr [esp+8],ebx
775d4303 c744241000000000 mov     dword ptr [esp+10h],0
775d430b 54              push    esp
775d430c e8ff4c0100      call    ntdll!RtlRaiseException (775e9010)
775d4311 c20800          ret     8

如果用ida可以的话就方便多了,下次找找ida的可行调试方法,ida调试老是报错不知道为啥

最最最刺激的来啦|他来啦

CreateProcess(…)我一直想试试,今天终于遇到了,一定要试一个痛快。

official-website

不过还是得从基本的函数参数开始,然后有一些参数设计一些略微复杂的结构体(主要是有些参数基本用不到)。皆さんこんじわ

//CreateProcessW function (processthreadsapi.h)
CreateProcess也有ANSI版本的,这里以UNICODE版本简述

//先上函数的声明,稍微有点长,不过萌大奶
BOOL CreateProcessW(
  LPCWSTR               lpApplicationName,
  LPWSTR                lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL                  bInheritHandles,
  DWORD                 dwCreationFlags,
  LPVOID                lpEnvironment,
  LPCWSTR               lpCurrentDirectory,
  LPSTARTUPINFOW        lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);

①从前两个开始,其实也是因为这俩兄弟相互有影响的
第一个名字,第二个命令行;一言概之是这样子的。不过也可以传入NULL。因此会稍微有一些复杂。
1.第一个不为NULL,第二个为NULL:
此时直接以第一个为命令行,进行检索时只会在本地目录下找一个可执行文件,或者由于传入的是一个完整的目录加文件名加后缀,到那个位置打开文件执行。
2.第一个为NULL,第二个不为NULL:
第二个参数如果是一个文件名,那么会被填充出后缀(exe这种)然后再去各个目录下查找有无。顺序参考:

1.The directory from which the application loaded.
2.The current directory for the parent process.
3.The 32-bit Windows system directory. Use the GetSystemDirectory function to get the path of this directory.
4.The 16-bit Windows system directory. There is no function that obtains the path of this directory, but it is searched. The name of this directory is System.
5.The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
6.The directories that are listed in the PATH environment variable. Note that this function does not search the per-application path specified by the App Paths registry key. To include this per-application path in the search sequence, use the ShellExecute function.

有点长,不过摩的关系。
3.两个都不为NULL:
就名字和命令行了。然后名字参考还是像lpApplicationName为NULL一样的规范,而命令行则是后面的那一串

②第三个第四个参数主要考虑进程和线程的安全性,这个都取NULL可以继承父进程的。也可以取一个 SECURITY_ATTRIBUTES structure来设置安全的属性

③第五个bInheritHandles这个主要考虑继承,可以通过这个防止子进程越权控制父进程的内核对象

④第六个dwCreationFlags主要用于设置新进程的优先级(通过标志位)
这个Mark一下,下次再细看

⑤第七个lpEnvironment是一个指向environment block的指针,如果为NULL可以继承父进程的,environment block指针则可以通过上文得到(阿巴阿巴)

⑥第八个lpCurrentDirectory一看就是指向当前目录的一个指针呗,也可以通过API获得

⑦第九个lpStartupInfo是
A pointer to a STARTUPINFO or STARTUPINFOEX structure

⑧第十个lpProcessInformation
A pointer to a PROCESS_INFORMATION structure that receives identification information about the new process

接下来开始激动人心的测试啦(其实有一些结构体的参数我还没仔细琢磨,不过萌大奶)

//这个程序能够打开一个notepad
#include <Windows.h>
#include <tchar.h>
#include <strsafe.h>


#ifndef _UNICODE
#define _UNICODE
#endif


int _tmain(int argc, TCHAR* argv[], TCHAR* env[])
{
	LPCWSTR lpAppName = NULL;
	LPWSTR lpCmdLine = new TCHAR;
	LPWSTR lpCmdLine = (LPWSTR)malloc(18);
	StringCchCopy(lpCmdLine, wcslen(L"notepad")+1, L"notepad");

	LPSECURITY_ATTRIBUTES lpProcessAttri = NULL;
	LPSECURITY_ATTRIBUTES lpThreadAttri = NULL;
	BOOL bInheritH = FALSE;

	DWORD dwCreadtionFlags = 0;
	// dwCreadtionFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP;
        //用上面这条语句贼能报错,现在还么研究透。
	LPVOID lpEnvironment = NULL;
	LPCWSTR lpCurrentDir = NULL;

	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si, sizeof(si));
	ZeroMemory(&pi, sizeof(pi));
	si.cb = sizeof(si);


	CreateProcessW(
		lpAppName,
		lpCmdLine,
		lpProcessAttri, 
		lpThreadAttri, 
		bInheritH,
		dwCreadtionFlags,
		lpEnvironment, 
		lpCurrentDir,
		&si, &pi);
	WaitForSingleObject(pi.hProcess, INFINITE);
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	return 0;
}

看看微软人家写的,我哭了

我又一次写出了屎山,太难受了。

我改进了一下,让进程自己创建新的自己。

#include <Windows.h>
#include <tchar.h>
#include <strsafe.h>


#ifndef _UNICODE
#define _UNICODE
#endif


int _tmain(int argc, TCHAR* argv[], TCHAR* env[])
{
	LPCWSTR lpAppName = NULL;
	LPWSTR lpCmdLine = (LPWSTR)malloc(18);
	StringCchCopy(lpCmdLine, wcslen(L"notepad")+1, L"notepad");
	LPWSTR lpCmdLine2 = (LPWSTR)malloc(30);
	StringCchCopy(lpCmdLine2, wcslen(L"ERROR_WATCH.exe") + 1, L"ERROR_WATCH.exe");

	LPSECURITY_ATTRIBUTES lpProcessAttri = NULL;
	LPSECURITY_ATTRIBUTES lpThreadAttri = NULL;
	BOOL bInheritH = FALSE;

	DWORD dwCreadtionFlags = 0;
	// dwCreadtionFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP;
	LPVOID lpEnvironment = NULL;
	LPCWSTR lpCurrentDir = NULL;

	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si, sizeof(si));
	ZeroMemory(&pi, sizeof(pi));
	si.cb = sizeof(si);


	CreateProcessW(
		lpAppName,
		lpCmdLine,
		lpProcessAttri, 
		lpThreadAttri, 
		bInheritH,
		dwCreadtionFlags,
		lpEnvironment, 
		lpCurrentDir,
		&si,
		&pi);

	CreateProcessW(
		lpAppName,
		lpCmdLine2,
		lpProcessAttri,
		lpThreadAttri,
		bInheritH,
		dwCreadtionFlags,
		lpEnvironment,
		lpCurrentDir,
		&si,
		&pi);
	WaitForSingleObject(pi.hProcess, INFINITE);
	CloseHandle(pi.hProcess);
	CloseHandle(pi.hThread);
	return 0;
}
//跑这个很危险,建议开虚拟机跑

读取进程的环境变量

甘了半天各种出错,mark一下一丢丢成果

//涉及一些Win32 Api
ExpandEnvironmentStringsA(
  LPCSTR lpSrc,
  LPSTR  lpDst,
  DWORD  nSize
);
//用于拓展可替换字符

LPWCH GetEnvironmentStringsW();
//用于返回一个指向进程环境变量的指针

DWORD GetEnvironmentVariableA(
  LPCSTR lpName,
  LPSTR  lpBuffer,
  DWORD  nSize
);
//用于确定某个环境变量是否存在

UINT SetErrorMode(
  UINT uMode
);
//设置系统如何处理错误(未对齐,文件查找错误等)

DWORD GetCurrentDirectory(
  DWORD  nBufferLength,
  LPTSTR lpBuffer
);
//获取当前目录

BOOL SetCurrentDirectory(
  LPCTSTR lpPathName
);
//设置当前目录

HANDLE CreateFileTransactedW(
  LPCWSTR               lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile,
  HANDLE                hTransaction,
  PUSHORT               pusMiniVersion,
  PVOID                 lpExtendedParameter
);
//判断windows系统版本
//也可以用GetVersion这个函数来整,还有一个结构体与之相关,应该挺有历史的OSVERSIONINFOEXA structure
#include <Windows.h>
#include <tchar.h>

#ifndef _UNICODE
#define _UNICODE
#endif

void ReadEnvBlock(LPWCH ptToEnv);

int _tmain(int argc,TCHAR* argv[],TCHAR* env[])
{
	for (int i = 0; i < 10; ++i)
	{
		wprintf(L"%s\n",env[i]);
	}
	wprintf(L"*****************\n");
	LPWCH ptToEnv = GetEnvironmentStringsW();
	ReadEnvBlock(ptToEnv);
	system("pause");
	return 0;
}

void ReadEnvBlock(LPWCH ptToEnv)
{
	while (ptToEnv != NULL)
	{
		if (*ptToEnv != L'=')
		{
			wprintf(L"%s\n", ptToEnv);
		}
		ptToEnv += wcslen(ptToEnv) + 1;
		if (*ptToEnv == L'\0')
		{
			break;
		}
	}
}

第一种方法是直接用main函数中的env参数直接读取,很方便
第二种就是用GetEnvironmentStringsW()读取进程环境变量,麻烦就在返回的宽字节指针是一个一维(客观由于环境变量的每个字符串不等长)的一个指针。于是写了一个轮子,运行起来还可以。

想起来今天贼尴尬的TCHAR宏定义问题,这个在编译器中就已经处理了,当我再次宏定义_UNICODE就改变不了TCHAR。

#include <Windows.h>
#include <tchar.h>

#ifndef _UNICODE
#define _UNICODE
#endif


int _tmain(int argc,TCHAR* argv[],TCHAR* env[])
{
	DWORD chValue = ExpandEnvironmentStrings(L"PATH='%PATH%'", NULL, 0);
	PTSTR pszBuffer = new TCHAR[chValue];
	chValue = ExpandEnvironmentStrings(L"PATH='%PATH%'", pszBuffer, chValue);
	_tprintf(L"%s", pszBuffer);
	delete[] pszBuffer;
	return 0;
}
//这个通过<!-- wp:enlighter/codeblock {"language":"cpp"} -->
<pre class="EnlighterJSRAW" data-enlighter-language="cpp" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">#include <Windows.h>
#include <tchar.h>

#ifndef _UNICODE
#define _UNICODE
#endif


int _tmain(int argc,TCHAR* argv[],TCHAR* env[])
{
	DWORD chValue = ExpandEnvironmentStrings(L"PATH='%PATH%'", NULL, 0);
	PTSTR pszBuffer = new TCHAR[chValue];
	chValue = ExpandEnvironmentStrings(L"PATH='%PATH%'", pszBuffer, chValue);
	_tprintf(L"%s", pszBuffer);
	delete[] pszBuffer;
	return 0;
}
//这个通过ExpandEnvironmentStrings函数拓展“可替换字符串”(比如%PATH%这种)返回一个指向拓展完成之后的字符串的指针。
//观察了一番发现我调用时先查询了系统的环境变量,再查询了用户的环境变量。
//那和进程的环境变量有什么关系呢?存疑嗷。
//可能有人会好奇为什么EpEnS执行了两次,第一次其实是为了返回拓展之后的长度,再分配内存给他。

进程“传递”内核对象的东东

怕忘记,就mark一下

第一种方法是在创建的时候直接创建可以继承的内核对象

//CreateProcessA function (processthreadsapi.h)
BOOL CreateProcessA(
  LPCSTR                lpApplicationName,
  LPSTR                 lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL                  bInheritHandles,
 
  DWORD                 dwCreationFlags,
  LPVOID                lpEnvironment,
  LPCSTR                lpCurrentDirectory,
  LPSTARTUPINFOA        lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);
//其中bInheritHandles是用于标志继承属性的,最后会在进程句柄表中标志位1之类
//对象句柄的继承只会在生成子进程的时候发生(也就是先删对象,就继承不到了;后来父继进程创建了新的对象,子也继承不到了)

②使用对象命名(能否传递也和内核对象是否全局有关(记不清了))

/*举一个创建的例子表明在哪可以写入对象名字(不过很多内核对象没名字,其实也就不用担心被别的调用或者“架空”(俺自己造的词),虽然不很清楚为什么)*/
HANDLE OpenMutex(
    DWORD dwDesireAccess,
    BOOL bInheritHandle,
    PCTSTR pszName);
//其中pszName就是可以写入名字的
//CreateMutexA function (synchapi.h)
HANDLE CreateMutexA(
  LPSECURITY_ATTRIBUTES lpMutexAttributes,
  BOOL                  bInitialOwner,
  LPCSTR                lpName
);
//lpName就可以传名字,如果有就忽略前两项了。
//坏蛋也可以通过名字的方法废掉一些内核对象(跃跃欲试),因为内核对象创建的时候不会检查是否覆盖。

③复制对象句柄(这个看了好久)

//DuplicateHandle function (handleapi.h)
BOOL DuplicateHandle(
  HANDLE   hSourceProcessHandle,
  HANDLE   hSourceHandle,
  HANDLE   hTargetProcessHandle,
  LPHANDLE lpTargetHandle,
  DWORD    dwDesiredAccess,
  BOOL     bInheritHandle,
  DWORD    dwOptions
);
//这个老折磨人了
第一个参数是进程S(Sourse)的handle,可以使用GetCurrentProcess()获得
第二个参数是进程要复制内核对象的句柄
第三个参数是目标进程的句柄
第四个参数记录着目标进程的句柄表中写入的索引位置(handle)
//来一个例子
HANDLE hObjInProcessS = CreateMutex(NULL,FALSE,NULL);
HANDLE hProcessT = OpenProcess(PROCESS_ALL_ACCESS,FALSE,dwProcessIdT);
HANDLE hObjInProcessT;
DuplicateHandle(GetCurrentProcess(),hObjInProcessS,hProcessT,&hObjInProcessT,0,FALSE,DUPLICATE_SAME_ACCESS)
//后面主要和传递过去内核对象的标志控制有关

这是什么妖怪

今天在逆向时进入一个_strlen函数。。

这个循环非常和善,用来确定eax的返回大小,表示字符串长度。

不过问题不在这,似乎我时被迷惑了

这个圈起来的给我看蒙了。这里改变了edx有什么用嘛,在这个函数结束之后,edx又被从栈中返回了,改变了eax,但是下面循环的时候eax也被重新赋值了,这就很迷惑=。=(太菜了)

C语言数字、指针、布尔值灵活利用的典范

先思考这个问题,假设我有一组数,我需要在每两个数字中间加入一个空格然后再输出出来,末尾和头部都没有空格,应该如何实现。

实现方法很简单,加个if就可以实现了,比如我想输出1 2 3 4 5 6,就可以这样:

#include<stdio.h>

int main()
{
	int arr[6] = { 1, 2, 3, 4, 5, 6 };
	for (int i = 0; i < 6; i++)
	{
		if (i == 5) //输出到最后一个数字了
			printf("%d", arr[i]);
		else
			printf("%d ", arr[i]);
	}
	return 0;
}

我们利用一个if语句来判断是否输出到最后一个数字,来选择是否输出占位的空格。事实上,也可以对第一个数字特殊对待,然后剩余数据输出时附带一个空格。

但是如果我们这么做呢:

#include<stdio.h>

int main()
{
	int arr[6] = { 1, 2, 3, 4, 5, 6 };
	for (int i = 0; i < 6; i++)
		printf(" %d" + !i, arr[i]);
	return 0;
}

极其简单的几句话完成了我们之前要的操作,一气呵成。

我详细叙述下它的过程:

玄机在于printf语句的那个加法上。C语言的字符串常量作参数,实际上是一个指向常量池中该字符串的指针,也就是可以进行运算。然后就是一个!i,这是把C语言中的整型数据当布尔值来看待,对他取非。当循环第一趟时,i=0,0在C语言中是false,非i得到true,默认为1,当那个指针+1,指针就从原来的指向空格,变成指向“%d”,那么就不会输出空格。而当之后几轮时,i均为非0数,C语言中为true,那么取非则得到false,即0,那么原指针+0,就是它本身,也就会正常输出空格,最后达到我们的要求。

这种写法说实话有很大局限性,可读性也极差,但是却很好的体现了C语言的灵活之处。C语言对数据和内存的操作极为灵活,这就要求使用者有很高的水平。这种写法不推荐在正式的程序设计中使用,但是对于开拓思维、优化程序是很有帮助的。

kali子系统启用root用户骚操作

kali平时使用大家都是直接用root用户,省(tou)事(lan)。

安装Windows的子系统的时候,kali会默认要求你创建新管理员用户,到时候再去删掉这个用户再启用root用户太麻烦了。

其实只要在第一次安装提示创建新用户的时候,直接关掉wsl再重新打开,你就会发现你直接使用默认的root用户登录了,非常偷懒。

LinkStart

到学校得路上贼坎坷,办好了麻烦事就可以开始啦*-*。

菱形继承虚表 看着好晕(等我看一遍C++再看吗。。)

买了本Windows程序设计,没想到是C#和XMHL相关,虽然似乎对学win32 API很有帮助就是,还有C++的面向对象的东西要看看。一下子就多了好多任务的亚子ToT。