2017-05-21 66 views
0

저는 어셈블리가 새롭고 현재 교육적 목적으로 조사하고있는 실행 파일이 있습니다. IDA 프로를 사용하여 실행 가능한 목적을 이해하고 있지만 몇 가지 질문이 있습니다. 여기 내 코드는 다음과 같습니다.어셈블리 : 두 개의 addres 추가하기

1.text:00401525     call ebp ; MapViewOfFile 
2.text:00401527     mov  ebp, eax 
3.text:00401529     test ebp, ebp 
4.text:0040152B     mov  [esp+54h+argv], ebp ; argv-shi ari chemi dll gadmotanili 
5.text:0040152F     jnz  short loc_401538 
6.text:00401531     push eax    ; Code 
7.text:00401532     call ds:exit 
8.text:00401538 ; --------------------------------------------------------------------------- 
9.text:00401538 
10.text:00401538 loc_401538:        ; CODE XREF: _main+EFj 
11.text:0040154C     mov  esi, [ebp+3Ch] 
12.text:0040154F     push ebp 
13.text:00401550     add  esi, ebp 
14.text:00401552     mov  ebx, eax 
15.text:00401554     push esi 
16.text:00401555     mov  [esp+68h+var_30], ebx 
17.text:00401559     mov  ecx, [esi+78h] 
18.text:0040155C     push ecx 
19.text:0040155D     call sub_401040 

제가 질문을 단순화하기 위해 열거했습니다.

1 호선에서 볼 수 있듯이 ebp에 함수가 호출되고 argv에 반환 주소가 저장됩니다 (kernel32.dll이 매핑 됨). 그 후 11 행 (내가 이해할 수있는 것처럼)에서 일부 함수 포인터는 esi으로 옮겨졌습니다. 3ch 십진수는 60이고 각 함수는 4 바이트입니다. kernel32.dll에서 내 보낸 모든 함수를 나열하고 15 번째 함수는 AddSecureMemoryCacheCallback입니다. 그런 다음 ebp이 스택에 푸시되고 13 행에서 완전히 혼란스러워졌습니다. 내가 이해할 때 말도 안되는 AddSecureMemoryCacheCallback을 가리키는 포인터로 시작하는 kernel32.dll의 포인터를 추가 할 것입니다.하지만이 포인터의 목적은 무엇입니까? 죄송합니다 내 질문에 어리석은 소리, 나는 새로운 어셈블리와 나는 너무 큰 때문에 전체 코드를 붙여 넣을 수 없습니다. 감사.

+0

나는 왜 당신이 수출 명부를보고 있는지 모른다. 'kernel32.dll'가 처음부터 매핑 되었다면,'ebp'는 MZ 헤더를 가리키고 있습니다. 오프셋 60은 PE 헤더에 대한 오프셋 인'e_lfanew'입니다. –

+0

정말 고마워요 :) 내가 말했듯이 나는 의회에서 새로 왔고, 무엇이 너무 보이는지 알지 못했다. 그러나 아직도 내게 불분명하다. 설명해 주시겠습니까? – Rasty

답변

2

함수는 함수가 성공하면 반환 값은 매핑 된 뷰의 시작 주소입니다 MapViewOfFile

반환 값
호출합니다.
함수가 실패하면 반환 값은 NULL입니다. 확장 된 오류 정보를 얻으려면 GetLastError를 호출하십시오.

이 코드는 최적화 된 코드이므로 ebp이 기본 포인터가 아닌 범용 레지스터로 사용됩니다.

1 call ebp ; MapViewOfFile 
2 mov  ebp, eax   //EBP = start address of mapped view. 
3 test ebp, ebp   //Success or failure? 
4 mov  [esp+54h+argv], ebp //save mapped address in a variable 
5 jnz  short loc_401538 //Success -> jump to loc_401538 
6 push eax     //failure -> clean up and exit. 
7 call ds:exit 
8 --------------------------------------------------------------------------- 
9 
10 loc_401538:        ; CODE XREF: _main+EFj 
11 mov  esi, [ebp+3Ch]  //esi = MappedFile.SomeOffset at addr 60 in the mapped file 
12 push ebp     //Param3 = Addr(MappedFile)    
13 add  esi, ebp    //esi = pointer(MappedFile.SomeOffset) 
14 mov  ebx, eax    //ebx = start of mapped file 
15 push esi     //Param2 = pointer(MappedFile.SomeOffset) 
16 mov  [esp+68h+var_30], ebx //store start of mapped file in some var 
17 mov  ecx, [esi+78h]  //ecx = MappedFile.SomeOffset-> = 120 
18 push ecx     //Param1 = MappedFile.SomeOffset[120] 
19 call sub_401040   //call subroutine(Param1, Param2, Param3) 

서브 루틴은 3 개 개의 매개 변수가 사용 cdecl calling convention을 갖는 함수이다. Param2와 Param3은 매핑 된 파일에 대한 포인터이고 param1은 알 수없는 데이터입니다.
매핑 된 파일의 파일 이름을 알고 있다면 hexeditor를 사용하여 데이터를보고 Offset 60에 저장된 오프셋을 확인한 다음 오프셋에 저장된 데이터를 계산할 수 있습니다 ([0+offset[60]][120]).

eax이 사용 가능하기 때문에 호출 된 서브 루틴은 값을 반환하는 경우가 많습니다. 귀하의 의견에 대해

이 조각은 Kernel32.dll에서 함수를 호출하는
당신의 가정은 잘못된 것입니다. 모든 포인터는 MapViewOfFile에 의해 반환 된 버퍼를 가리키고 코드가하는 일을 이해하기 위해 특정 파일의 내용을 연구해야합니다.

레지스터를 밀어 넣는 작업은 단순히 cdecl 호출 규칙입니다. 이 코드는 c 코드이므로 내부적으로 cdecl 호출 규칙을 사용하므로 스택을 사용하여 모든 매개 변수를 전송해야합니다.
외부에서 레지스터의 처음 3 개 매개 변수를 전송하는 stdcall을 사용합니다.

stdcallcdecl은 모두 EAX입니다.

+0

답변을 주셔서 대단히 감사합니다 :)하지만 13 행에'add esi, ebp'는'MappedFile.SomeOffset'의 포인터를 esi로 옮기는'lea esi, ebp '가 아니겠습니까? – Rasty

+0

당신이'lea esi, [ebp + esi]'를 의미했다고 확신합니다. 예, 작동 할 것이지만'add reg, reg'는 2 바이트이고'lea reg, [reg + reg]'는 3 바이트입니다. 그래서 add가 더 효율적입니다. 마지막 오프셋 @ 120은 포인터에 대한 포인터를 사용하여 역 참조됩니다. 따라서 거기에 도착하려면 2 단계가 필요하므로 추가하십시오. – Johan

+0

죄송합니다. 조금 혼란 스럽 습니다만, 'add'명령으로 레지스터에 저장된 값을 합산해서는 안됩니까? 왜 그것은 한 레지스터의 포인터를 다른 레지스터에 저장합니까? – Rasty