문제

저는 어셈블러, C++ 및 PE 파일 작동 방식에 대해 자세히 알아보기 위해 exe 패커/보호기를 코딩하려고 합니다.현재 작동 중이므로 EP가 포함된 섹션이 키와 XOR되고 내 암호 해독 코드가 포함된 새 섹션이 생성됩니다.암호 해독 후 원본 EP에 JMP를 시도하는 경우를 제외하고는 모든 것이 잘 작동합니다.

기본적으로 나는 이렇게 한다:

DWORD originalEntryPoint = optionalHeader->AddressOfEntryPoint;
// -- snip -- //
    crypted.put(0xE9);
 crypted.write((char*)&orginalEntryPoint, sizeof(DWORD)); 

그러나 진입점으로 점프하는 대신 ollydbg는 이 코드가 다음과 같이 분해되는 것을 보여줍니다.

00404030   .-E9 00100000    JMP 00405035 ; should be 00401000 =[

olly에서 수동으로 변경하려고 하면 새 opcode가 다음과 같이 표시됩니다.

00404030    -E9 CBCFFFFF    JMP crypted.00401000

0xCBCFFFFF는 어디에서 왔습니까?C++ 측에서 어떻게 생성합니까?

도움이 되었습니까?

해결책

내 생각에는 E9 상대 점프를위한 opcode입니다. 오페라는 점프 할 상대 거리를 지정하고 다음 명령어의 시작 부분에서 + 또는 마이너스를 지정합니다.

피연산자가 절대 주소를 지정하려면 다른 opcode가 필요합니다.

다른 팁

당신은 사용할 수 있습니다 :

mov eax,DESTINATION_VA
jmp eax                ; pick any register the destination doesn't care about

또는

push DESTINATION_VA
ret                    ; not recommended for performance

이것은 다음과 16까지입니다 ret 이 깊이보다 더 높은 콜 트리를 백업하는 지침은 더 깊은 콜 깊이에 의해 리턴 드레스 예측기 스택을 밀어 내지 않는 한 오해가됩니다. (현재 CPU는 일반적으로 16 입력 예측기 스택이 있습니다).


상대적인 E9 jmp 인코딩은 다음과 같이 사용됩니다.

CURRENT_RVA: jmp (DESTINATION_RVA - CURRENT_RVA - 5 [sizeof(E9 xx xx xx xx)])

푸시 + ret는 VA 주소가 있고 이미지가 재배치되지 않은 경우 가장 작은 솔루션이지만 여전히 6 바이트이므로 직접보다 큽니다. jmp rel32.

정상 직접을 사용할 수 없다면 레지스터 간질은 아마도 가장 효율적일 것입니다. jmp.

절대 간접 점프를 위한 opcode는 FF + 4바이트 주소입니다.이는 데이터에 저장된 주소의 점프 테이블에 가장 자주 사용됩니다.

절대 주소는 예상 주소에 로드되지 않은 경우 재배치가 필요하므로 일반적으로 상대 주소가 선호됩니다.상대 점프를 위한 코드도 2바이트 더 작습니다.

Intel 최적화 매뉴얼에는 CPU가 call과 ret이 쌍으로 사용될 것으로 예상하므로 답변 2에서 제안된 호출 없이 ret을 사용하면 "성능 저하"가 발생할 수 있다고 명시되어 있습니다.

또한 코드가 컴파일러가 가정한 것과 동일한 주소에 로드되지 않은 경우 ret으로 인해 프로그램이 중단될 수 있습니다.상대 주소를 계산하는 것이 더 안전할 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top