우선 전의 문제들과 같이
chall3.00007FF7E4EB1024
이 부분에서 rsp를 1씩 늘려가면서 제가 넣은 문자열과 [7FF7E4EB3000]
의 문자열을 비교하는 내용인 것 같습니다.
movsxd rax, dword ptr ss:[rsp]
lea rcx, qword ptr ds: [7FF7E4EB3000]
movsxd rcx, dword ptr ss:[rsp]
을 통해 비교해야 될([7FF7E4EB3000]
) 문자들을 루프할 때마다 rsp
를 1씩 늘려가면서 하나씩 가져오는것 같고
movsxd rcx,dword ptr ss:[rsp]
mov rdx, qword ptr ss:[rsp+20]
movzx ecx, byte ptr ds:[rdx+rcx]
을 통해 제가 입력하게 될 문자들을 루프할 때마다 rsp
를 1씩 늘려가면서 하나씩 ecx
에 넣는것 같습니다.
ㅡㅡㅡㅡㅡ
그런데 여기서부터 너무 햇갈리기 시작합니다.
제가 abcd
를 넣었다고 가정하면
xor ecx, dword ptr ss:[rsp]
mov edx, dword ptr ss:[rsp]
lea ecx, qword ptr ds:[rcx+rdx*2]
이 부분에서
ecx = a xor 0
ecx = b xor 1
ecx = c xor 2
ecx = d xor 3
입력한 문자가 맞다면 이런식으로 xor을 해 나갈텐데
lea
는 분명히 오른쪽에 주소가 와야된다고 알고있는데 rcx+rdx * 2
가 주소가 맞는지조차 모르겠고
아니면 rcx+rdx*2
의 연산 결과값을 주소로 쓰는건지 잘 모르겠습니다.
a xor 0
은 a이니까 a(0x61) + 0 * 2
면 0xC2
인데 너무 짧아서 이걸로 주소를 찾을수 있는지도 모르겠고
잠시 넘어가서
cmp eax, ecx
는 비교하고 맞게 입력했으면 루프를 반복하고 잘못 입력했으면 0을 리턴해서 wrong이 나오게 되는것 같습니다.
그러니까 어쨌든간에 lea를 사용했으니까 결과적으로 cmp eax, ecx
를 할 때
eax
의 [7FF7E4EB3000]
의 0번째 바이트와 ecx
주소의 0번째 녀석 혹은 ecx
주소의 값과 비교하는걸텐데
0번째 녀석이면 rdx
는 인덱스의 역할을 하는걸테고 근데 qword
로 되어있으니까 8바이트를 가져오는걸텐데 그럼 *2는 무슨뜻인지 모르겠고
ecx의 주소의 값과 비교한다고 해도
? xor 0 -> + 0 * 2 -> 49
? xor 1 -> + 1 * 2 -> 60
? xor 2 -> + 2 * 2 -> 67
? xor 3 -> + 3 * 2 -> 74
? xor 4 -> + 4 * 2 -> 63
? xor 5 -> + 5 * 2 -> 67
? xor 6 -> + 6 * 2 -> 42
이렇게 되어야 될 것 같은데 여기서 역연산을 하게되면
컴퓨터는 연산은 사칙연산 규칙을 따르지 않고 무조건 앞에서부터 연산하는 방식이라고 이라고 읽었습니다.
그러면 49 / 2 - 0 ^ 0
을 순서대로하면 될거같지만 49/2부터 이미 뭔가 이상해진거같고 어디서부터 잘못된지 모르겠습니다.
특히 저를 너무 혼란스럽게 만드는
lea ecx, qword ptr ds:[rcx+rdx*2]
이부분만 보면 오른쪽에 주소가 와야될거같은데 아니면 mov
가 와야되는게 아닌지부터 시작해서 처음보는 형태라 생각이 너무 혼란스럽게 됩니다 ㅠㅠ
제대로 모르다보니 질문조차도 너무 복잡한거같은데 머릿속이 너무 혼란스러워서 잘못 말씀드릴까봐 최대한 횡설수설하지 않으려고 노력했습니다ㅜㅜ
죄송합니다...
감도 안 잡힌다는게 제 상태와 맞는 말인 것 같습니다...ㅜㅜ
어떤식으로 접근하셨고 진행 상황을 자세히 알려주시면 도와드리겠습니다.
lea 인스트럭션은 기본적으로 메모리의 주소를 로드하기 위해 사용하는 인스트럭션이 맞습니다.
lea rax, qword ptr ds:[address]
는 이해하신대로 rax 레지스터에 address 주소를 넣는다는 것을 의미하는 인스트럭션입니다. 즉 C언어로 표현하면 rax = address;
라고 표현할 수 있습니다.
lea 인스트럭션의 기본적인 목적은 주소를 로드하는 것이 맞지만 반드시 우변에 메모리의 주소만 올 수 있는 것은 아닙니다.
cpu는 lea 인스트럭션을 실행하면서 우변에 오는 주소가 실제로 매핑되어있는 주소가 아니더라도 그대로 레지스터에 로드합니다.
즉 lea rax, qword ptr ds:[0x4141414141414141]
과 같이 존재하지 않는 주소일지라도 cpu는 이를 정상적으로 실행할 수 있습니다.
처음에 C언어로 표현했던 방식대로 위 인스트럭션을 다시 표현하면 rax = 0x4141414141414141;
의 형태로 표현될 수 있게 됩니다.
따라서 질문주신 lea ecx, qword ptr ds:[rcx+rdx*2]
인스트럭션은 ecx = rcx+rdx*2;
와 똑같은 산술 연산으로 표현할 수 있게 됩니다.
cpu는 rcx+rdx*2
연산 결과가 정상적인 주소인지에 대한 여부와는 관계 없이 ecx에 바로 로드하기 때문에 표현된 산술 연산을 수행하는 것과 똑같은 결과를 ecx에 저장하게 됩니다.
이런 방식으로 산술 연산을 처리하는 이유는 mov, add, mul 세 개의 인스트럭션으로 나눠서 산술 연산을 처리하는 것보다 하나의 lea 인스트럭션을 이용해서 산술 연산을 수행하는 것이 훨씬 효율적이기 때문입니다.
x64dbg를 이용해서 해당 인스트럭션을 실행시켜보면 실제로 ecx에 산술 연산을 수행한 결과가 저장되는 것을 확인할 수 있습니다.