Programing

학습 어셈블리

lottogame 2020. 8. 20. 19:27
반응형

학습 어셈블리


나는 어셈블리 언어를 배우기로 결정했습니다. 그렇게하는 주된 이유는 분해 된 코드를 이해할 수 있고 아마도 코드의 더 효율적인 부분 (예 : C ++를 통해)을 작성할 수 있고 코드 동굴과 같은 작업을 수행 할 수 있기 때문입니다. 어셈블리에는 수많은 종류가 있다는 것을 알았습니다. , 내가 언급 한 목적을 위해 어떻게 시작해야합니까? 어떤 종류의 어셈블리를 배워야합니까? 먼저 간단한 프로그램 (예 : 계산기)을 수행하여 배우고 싶지만 목표 자체는 IDA Pro가 보여주는 코드를 이해할 수 있도록 그것에 익숙해지는 것입니다.

나는 창문을 사용하고 있습니다 (그게 차이가 있다면).

편집 : 그래서 모든 사람들이 MASM을 가리키는 것 같습니다. 높은 수준의 기능이 있고 어셈블리 코드 프로그래머에게 모두 좋다는 점을 알지만, 그것은 내가 찾던 것이 아닙니다. 인기있는 디 어셈블러 (IDA와 같은)에 표시되지 않은 if, invoke 등의 명령어가있는 것 같습니다. 그래서 가능하다면 듣고 싶은 것은 "일반적인"어셈블리 프로그래머가 아니라 내가 묻는 목적 (IDA에서 분해 된 exe의 코드 읽기)을 위해 ASM을 사용하는 사람의 의견입니다.

편집 : 좋아. 나는 이미 어셈블리를 배우고 있습니다. 나는 나에게 중요하지 않은 높은 수준의 물건을 사용하지 않고 MASM을 배우고 있습니다. 내가 지금하고있는 것은 C ++의 __asm ​​지시문에 대한 내 코드를 시험하는 것이므로 MASM으로 모든 것을 처음부터해야하는 것보다 훨씬 빠르게 작업을 시도 할 수 있습니다.


MASM32로 시작하고 거기서부터 FASM을 살펴보십시오 . 그러나 당신은 MASM으로 재미있게 지낼 것입니다.


나는 이것을 여러 번했고 이것을 계속한다. 이 경우 기본 목표가 어셈블러를 작성하지 않고 읽는 것입니다.

자신의 디스어셈블러를 작성하십시오. 다음으로 위대한 디스어셈블러를 만들기위한 것이 아니라, 이것은 엄격히 당신을위한 것입니다. 목표는 명령어 세트를 배우는 것입니다. 새로운 플랫폼에서 어셈블러를 배우 든, 한때 알고 있던 플랫폼의 어셈블러를 기억합니다. 몇 줄의 코드로 시작하고, 예를 들어 레지스터를 추가하고, 이진 출력을 분해하고 입력 측에 점점 더 복잡한 명령어를 추가하는 사이에 핑퐁을 사용합니다.

1) 특정 프로세서에 대한 명령어 세트 학습

2) 모든 명령어에서 모든 opcode 비트를 흔들 수 있도록 상기 프로세서에 대해 어셈블에서 코드를 작성하는 방법의 뉘앙스를 배웁니다.

3) 그 명령 세트를 사용하여 생계를 유지하는 대부분의 엔지니어보다 명령 세트를 더 잘 배웁니다.

귀하의 경우 몇 가지 문제가 있습니다. 일반적으로 ARM 명령어 세트를 시작하는 것이 좋습니다. 오늘 출하되는 ARM 기반 제품이 다른 어떤 것보다 많습니다 (x86 컴퓨터 포함). 그러나 현재 ARM을 사용하고 있고 ARM이 수행하려는 작업에 도움이 될 수도 있고 도움이되지 않을 수도 있다는 것을 알고있는 시작 코드 또는 기타 루틴을 작성하기에 충분한 어셈블러를 알지 못할 가능성이 있습니다. ARM 우선의 두 번째이자 더 중요한 이유는 명령어 길이가 고정 된 크기이고 정렬되기 때문입니다. x86과 같은 가변 길이 명령어를 분해하는 것은 첫 번째 프로젝트로 악몽이 될 수 있으며 여기서 목표는 연구 프로젝트를 만들지 않는 명령어 세트를 배우는 것입니다. 세 번째 ARM은 잘 수행 된 명령어 세트이며 레지스터는 동일하게 생성되며 개별적인 특별한 뉘앙스가 없습니다.

따라서 시작하려는 프로세서를 파악해야합니다. msp430 또는 ARM을 먼저 제안하고 ARM을 먼저 또는 두 번째로 x86의 혼돈을 제안합니다. 어떤 플랫폼을 사용하든 사용할 가치가있는 모든 플랫폼에는 명령 세트와 연산 코드 (기계 언어의 비트 및 바이트) 인코딩이 포함 된 공급 업체에서 무료로 제공하는 데이터 시트 또는 프로그래머 참조 설명서가 있습니다. 컴파일러가하는 일과 컴파일러가 고생 할 필요가없는 코드를 작성하는 방법을 배우기 위해서는 몇 개의 명령어 세트를 알고 각 최적화를 통해 각 컴파일러의 각 명령어 세트에서 동일한 상위 레벨 코드가 어떻게 구현되는지 확인하는 것이 좋습니다. 환경. 하나의 컴파일러 / 플랫폼에 대해서는 더 좋게 만들었지 만 다른 모든 것에 대해서는 훨씬 더 나쁘게 만들기 위해 코드를 최적화하는 것을 원하지 않습니다.

ARM과 같이 또는 msp430과 같이 2 바이트마다 메모리를 통해 단순히 처음부터 시작하여 4 바이트 워드마다 선형 적으로 분해하는 대신 가변 길이 명령어 세트를 디스 어셈블하는 것이 좋습니다 (msp430에는 가변 길이 명령어가 있지만 여전히 인터럽트 벡터 테이블의 진입 점에서 시작하면 메모리를 통해 선형으로 이동). 가변 길이의 경우 벡터 테이블 또는 프로세서 부팅 방법에 대한 지식을 기반으로 진입 점을 찾고 실행 순서대로 코드를 따르고 싶습니다. 사용 된 바이트 수를 알기 위해 각 명령어를 완전히 디코딩해야합니다. 그러면 명령어가 무조건 분기가 아닌 경우 해당 명령어 이후의 다음 바이트가 다른 명령어라고 가정합니다. 가능한 모든 분기 주소도 저장해야하며 더 많은 지침을 위해 시작 바이트 주소라고 가정해야합니다. 한 번 성공했을 때 바이너리를 여러 번 통과했습니다. 진입 점에서 시작하여 해당 바이트를 명령어의 시작으로 표시 한 다음 무조건 분기에 도달 할 때까지 메모리를 통해 선형으로 디코딩했습니다. 모든 분기 대상은 명령어의 시작 주소로 태그가 지정되었습니다. 새 분기 대상을 찾을 수 없을 때까지 바이너리를 여러 번 통과했습니다. 언제라도 3 바이트 명령어를 찾았지만 어떤 이유로 두 번째 바이트를 명령어의 시작으로 태그 한 경우 문제가 있습니다. 코드가 상위 수준의 컴파일러에 의해 생성 된 경우 컴파일러가 악의적 인 작업을 수행하지 않는 한 발생해서는 안됩니다. 코드에 손으로 작성된 어셈블러 (예 : 오래된 아케이드 게임)가있는 경우 r0 = 0과 같이 발생하지 않는 조건부 분기가있을 수 있으며 0이 아니면 점프가 이어질 수 있습니다. 계속하려면 바이너리에서 직접 편집해야 할 수도 있습니다. 내가 x86에 있다고 가정하는 즉각적인 목표에 대해서는 문제가 있다고 생각하지 않습니다.

gcc 도구를 권장합니다. mingw32는 x86이 대상인 경우 Windows에서 gcc 도구를 사용하는 쉬운 방법입니다. mingw32 plus msys는 binutils 및 gcc 소스에서 크로스 컴파일러를 생성하기위한 훌륭한 플랫폼입니다 (일반적으로 매우 쉽습니다). mingw32는 훨씬 빠른 프로그램과 같이 cygwin에 비해 몇 가지 장점이 있으며 cygwin dll 지옥을 피할 수 있습니다. gcc 및 binutils를 사용하면 C 또는 어셈블러로 작성하고 코드를 디스 어셈블 할 수 있으며 세 가지 중 하나 또는 모두를 수행하는 방법을 보여주는 웹 페이지가 읽을 수있는 것보다 많습니다. 가변 길이 명령어 세트로이 작업을 수행하려면 디스어셈블러가 포함 된 도구 세트를 사용하는 것이 좋습니다. 예를 들어 x86 용 써드 파티 디스어셈블러는 올바르게 디스 어셈블되었는지 알 수 없기 때문에 사용하기 어려울 것입니다. 이 중 일부는 운영 체제에 따라 다릅니다. 목표는 디스어셈블러가보다 정확한 작업을 수행 할 수 있도록 데이터의 정보 표시 명령을 포함하는 이진 형식으로 모듈을 컴파일하는 것입니다. 이 기본 목표에 대한 다른 선택은 검사를 위해 어셈블러로 직접 컴파일 할 수있는 도구를 보유한 다음 바이너리 형식으로 컴파일 할 때 동일한 명령어를 생성하기를 바라는 것입니다.

The short (okay slightly shortER ) answer to your question. Write a disassembler to learn an instruction set. I would start with something RISCy and easy to learn like ARM. Once you know one instruction set others become much easier to pick up, often in a few hours, by the third instruction set you can start writing code almost immediately using the datasheet/reference manual for the syntax. All processors worth using have a datasheet or reference manual that describes the instructions down to the bits and bytes of the opcodes. Learn a RISC processor like ARM and a CISC like x86 enough to get a feel for the differences, things like having to go through registers for everything or being able to perform operations directly on memory with fewer or no registers. Three operand instructions versus two, etc. As you tune your high level code, compile for more than one processor and compare the output. The most important thing you will learn is that no matter how good the high level code is written the quality of the compiler and the optimization choices made make a huge difference in the actual instructions. I recommend llvm and gcc (with binutils), neither produce great code, but they are multi platform and multi target and both have optimizers. And both are free and you can easily build cross compilers from sources for various target processors.


손으로 작성하는 어셈블리와 컴파일러에서 생성 한 어셈블리는 높은 수준에서 볼 때 종종 매우 다릅니다. 물론, 프로그램의 내부는 매우 유사 할 것입니다 (결국 인코딩하는 방법은 매우 다양 a = b + c합니다).하지만 리버스 엔지니어링을 시도 할 때 문제가되지는 않습니다. 컴파일러가 추가됩니다 도 간단한 실행 파일에 상용구 코드를 : 어셈블리에 손으로 쓴 경우는 약 100 바이트의 동안 비교 마지막 시간, GCC에 의해 컴파일에 "Hello World"는 4kB의에 대해이었다. Windows에서는 더 나쁩니다. 마지막으로 비교했을 때 (확실히 이것은 지난 세기였습니다.) 내가 생성 할 윈도우 컴파일러를 얻을 수있는 가장 작은 "Hello World"는 52kB였습니다! 일반적으로이 상용구는 한 번만 실행되므로 프로그램 속도에 큰 영향을주지 않습니다. 위에서 말했듯이 프로그램의 핵심 인 실행 시간이 가장 많이 소요되는 부분은 일반적으로 컴파일 또는 손으로 쓴다.

결국 이것은 전문 어셈블리 프로그래머 와 전문 디스어셈블러 가 서로 다른 두 가지 전문 분야 라는 것을 의미합니다 . 일반적으로 그들은 같은 사람에게서 발견되지만 실제로는 분리되어 있으며 훌륭한 어셈블리 코더가되는 방법을 배우는 것은 리버스 엔지니어링을 배우는 데 그다지 도움이되지 않습니다.

원하는 것은 IntelAMD 의 IA-32 및 AMD64 (둘 다 함께 다룹니다) 아키텍처 설명서를 가져 와서 지침 및 opcode에 대한 초기 섹션을 살펴 보는 것입니다. 어셈블리 언어의 기초를 이해하기 위해 어셈블리 언어에 대한 자습서를 한두 개 읽을 수 있습니다. 그런 다음 작은관심이있는 샘플 프로그램을 분해하고 제어 흐름을 단계별로 살펴보고 무엇을하는지 이해하려고합니다. 다른 작업을 수행하기 위해 패치 할 수 있는지 확인하십시오. 그런 다음 다른 프로그램으로 다시 시도하고 더 유용한 목표를 달성 할 수있을만큼 편안해질 때까지 반복하십시오. 리버스 엔지니어링 커뮤니티에서 제작 한 "크랙"과 같은 것에 관심이있을 수 있습니다. 리버스 엔지니어링에 관심이있는 사람들이 직접 시도해보고 그 과정에서 무언가를 배우기를 바랍니다. 난이도는 기본 (여기서 시작하세요!)에서 불가능까지 다양합니다.

무엇보다도, 당신은 할 필요가 연습 . 다른 많은 분야에서와 마찬가지로 리버스 엔지니어링을 사용하면 연습이 완벽하거나 적어도 더 좋습니다 .


나는 대부분의 대답에 반대 하고 MIPS RISC 아키텍처의 Knuth의 MMIX 변형을 권장 합니다. x86 또는 ARM 어셈블리 언어만큼 실질적으로 유용하지는 않을 것입니다 (요즘 대부분의 실제 작업에서 그 자체로 중요하다는 것은 아닙니다 ... ;-).하지만 Knuth의 최신 기술의 마법을 잠금 해제 할 것입니다. 알고리즘과 데이터 구조에 대한 깊은 저수준 이해에 관한 역사상 가장 위대한 걸작의 버전 인 TAOCP , "컴퓨터 프로그래밍 기술". 내가 인용 한 두 URL의 링크는 이러한 가능성을 탐색하는 좋은 방법입니다!


(당신은 모르지만 조립에 신이 났어요)

조립을 실험하기위한 간단한 도구가 이미 PC에 설치되어 있습니다.

시작 메뉴-> 실행으로 이동하여debug

debug (명령)

debug 는 DOS, MS-DOS, OS / 2 및 Microsoft Windows (x64가 아닌 x86 버전 만 해당)의 명령으로 debug.exe (또는 이전 버전의 DOS에서는 DEBUG.COM)를 실행합니다. 디버그는 어셈블러, 디스어셈블러 또는 16 진 덤프 프로그램으로 작동하여 사용자가 메모리 콘텐츠 (어셈블리 언어, 16 진수 또는 ASCII)를 대화 형으로 검사하고 변경하고 COM, EXE 및 기타 파일 형식을 선택적으로 실행할 수 있도록합니다. 또한 특정 디스크 섹터, I / O 포트 및 메모리 주소에 액세스하는 데 사용되는 여러 하위 명령이 있습니다. MS-DOS 디버그는 16 비트 프로세스 수준 에서 실행 되므로 16 비트 컴퓨터 프로그램으로 제한됩니다 . FreeDOS Debug에는 32 비트 DPMI 프로그램도 지원하는 "DEBUGX"버전이 있습니다.

튜토리얼 :


IDA Pro (또는 OllyDbg ) 에서 볼 수있는 코드를 이해하려면 컴파일 된 코드가 어떻게 구성되는지 배워야합니다. Reversing : Secrets of Reverse Engineering 책을 추천합니다 .

저는 debug어셈블리를 배우기 시작했을 때 (15 년 전) 몇 주 동안 실험했습니다 .
참고 것을 debug기본 시스템 수준의 작품, 더 높은 수준의 어셈블리 명령이 없습니다.

이제 간단한 예제 :

부여 a어셈블리 코드를 작성 시작 - 프로그램 아래를 입력 - 마지막 줄 g을 실행합니다.

대체 텍스트


( 레지스터가 설정된 경우 레지스터에 INT 21저장된 ASCII 문자를 화면에 표시 - 프로그램 종료)DLAH2INT 20


내가 발견 착취의 예술 : 해킹을 내가 직접 지식을 사용했다고 말할 수 없다 ...이 주제로 재미 있고 유용한 방법이 될,하지만 난 그것을 읽고 그 이유는 정말 아니다. 코드가 컴파일되는 지침을 훨씬 더 풍부하게 이해할 수 있으며, 이는 때때로 미묘한 버그를 이해하는 데 유용했습니다.

제목으로 미루지 마십시오. 이 책의 첫 번째 부분의 대부분은 Eric Raymond라는 단어의 의미에서 "해킹"입니다. 어려운 문제를 해결하는 창의적이고 놀랍고 거의 교활한 방법입니다. 저 (그리고 아마도 당신)는 보안 측면에 훨씬 덜 관심을 가졌습니다.


적어도 처음에는 어셈블리로 프로그램을 작성하는 데 집중하지 않을 것입니다. x86을 사용하고 있다면 (Windows를 사용하고 있기 때문에 그렇다고 가정합니다) 배우는 것이 무의미한 이상한 특수 사례가 많이 있습니다. 예를 들어 많은 명령어는 명시 적으로 이름을 지정하지 않은 레지스터에서 작동한다고 가정하고 다른 명령어는 일부 레지스터에서는 작동하지만 다른 명령어에서는 작동하지 않는다고 가정합니다.

나는 당신이 의도 한 아키텍쳐에 대해 당신이 기초를 이해하는만큼 충분히 배운 다음 바로 들어가서 컴파일러의 출력을 이해하려고 노력할 것입니다. 인텔 매뉴얼로 무장 하고 컴파일러의 출력으로 바로 들어가십시오. 관심있는 코드를 작은 함수로 분리하면 전체 내용을 확실히 이해할 수 있습니다.

기본 사항은 다음과 같습니다.

  • 레지스터 : 몇 개가 있고, 이름이 무엇이며, 크기가 무엇입니까?
  • 피연산자 순서 : add eax, ebx"eax에 ebx를 추가하고 결과를 eax에 저장"을 의미합니다.
  • FPU : 부동 소수점 스택의 기본 사항과 fp로 /에서 변환하는 방법을 배웁니다.
  • 주소 지정 모드 : [base + offset * multiplier], 그러나 multiplier는 1, 2 또는 4 (또는 8?) 만 가능합니다.
  • 호출 규칙 : 매개 변수가 함수에 어떻게 전달됩니까?

많은 시간 동안 컴파일러가 무엇을 내보내는 지 놀라 울 것입니다. 왜 컴파일러가 이것이 좋은 생각이라고 생각했는지 알아내는 퍼즐을 만드십시오. 당신에게 많은 것을 가르쳐 줄 것입니다.

또한 Agner Fog의 매뉴얼 , 특히 지침 목록을 사용 하여 무장하는 데 도움이 될 것입니다 . 최신 프로세서에서 직접 수량화하기는 더 어렵지만 각 명령어의 대략적인 비용을 알려줍니다. 그러나 예를 들어 컴파일러가 idiv명령어 발행을 피하기 위해 그렇게 멀리 나가는 이유를 설명하는 데 도움이 될 것 입니다.

저의 유일한 조언은 선택권이있을 때 항상 AT & T 대신 인텔 구문을 사용하는 것입니다. 나는이 점에 대해 꽤 중립적이었다. 두 가지 명령어가 완전히 다르다는 것을 깨달을 때까지 (예를 들어 movslqAT & T 구문은 movsxdIntel 구문 임). 매뉴얼은 모두 인텔 구문을 사용하여 작성되었으므로 그대로 유지하십시오.

행운을 빕니다!


저는 매우 컴팩트 한 32 비트 아키텍처 인 MIPS를 배우기 시작했습니다. 축소 된 명령어 세트이지만 초보자도 쉽게 이해할 수 있습니다. 복잡성에 압도되지 않고 어셈블리가 어떻게 작동하는지 이해할 수 있습니다. MIPS 코드를 컴파일 할 수있는 멋진 IDE를 다운로드 할 수도 있습니다. clicky 일단 익숙해 지면 더 복잡한 아키텍처로 이동하는 것이 훨씬 더 쉬울 것이라고 생각합니다. 적어도 그것이 내가 생각했던 것입니다 :)이 시점에서 당신은 메모리 할당 및 관리, 논리 흐름, 디버깅, 테스트 등에 대한 필수 지식을 갖게 될 것입니다.


디버그 사용에 대한 제안은 재미있는 것입니다. 많은 깔끔한 트릭을 사용할 수 있습니다. 그러나 최신 운영 체제의 경우 16 비트 어셈블리를 배우는 것이 약간 덜 유용 할 수 있습니다. 대신 ntsd.exe를 사용해보십시오. Windows XP에 내장되어 있습니다 (불행히도 Server 2003 이상에서 제거됨). 매우 널리 사용되기 때문에 배우기 편리한 도구입니다.

즉, XP의 원래 버전에는 많은 버그가 있습니다. 정말로 그것을 사용하고 싶다면 (또는 동일한 명령 구문과 디버깅 백엔드를 가진 본질적으로 다른 인터페이스 인 cdb 또는 windbg), 무료 Windows 디버깅 도구 패키지를 설치해야 합니다.

해당 패키지에 포함 된 debugger.chm 파일은 비정상적인 구문을 알아 내려고 할 때 특히 유용합니다.

ntsd의 가장 큰 장점은 가까이있는 모든 XP 시스템에서 팝업하여 조립하거나 분해하는 데 사용할 수 있다는 것입니다. / great / X86 어셈블리 학습 도구를 만듭니다. 예를 들어 (dos 프롬프트에서 인라인이므로 cdb 사용, 그렇지 않으면 동일합니다) :

(기호 오류는 관련이 없기 때문에 건너 뛰었습니다. 또한이 서식이 작동하기를 바랍니다. 이것이 제 첫 게시물입니다)

C:\Documents and Settings\User>cdb calc

Microsoft (R) Windows Debugger Version 6.10.0003.233 X86
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: calc
Symbol search path is: *** Invalid ***
Executable search path is:
ModLoad: 01000000 0101f000   calc.exe
ModLoad: 7c900000 7c9b2000   ntdll.dll
ModLoad: 7c800000 7c8f6000   C:\WINDOWS\system32\kernel32.dll
ModLoad: 7c9c0000 7d1d7000   C:\WINDOWS\system32\SHELL32.dll
ModLoad: 77dd0000 77e6b000   C:\WINDOWS\system32\ADVAPI32.dll
ModLoad: 77e70000 77f02000   C:\WINDOWS\system32\RPCRT4.dll
ModLoad: 77fe0000 77ff1000   C:\WINDOWS\system32\Secur32.dll
ModLoad: 77f10000 77f59000   C:\WINDOWS\system32\GDI32.dll
ModLoad: 7e410000 7e4a1000   C:\WINDOWS\system32\USER32.dll
ModLoad: 77c10000 77c68000   C:\WINDOWS\system32\msvcrt.dll
ModLoad: 77f60000 77fd6000   C:\WINDOWS\system32\SHLWAPI.dll
(f2c.208): Break instruction exception - code 80000003 (first chance)
eax=001a1eb4 ebx=7ffd6000 ecx=00000007 edx=00000080 esi=001a1f48 edi=001a1eb4
eip=7c90120e esp=0007fb20 ebp=0007fc94 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
ntdll!DbgBreakPoint:
7c90120e cc              int     3
0:000> r eax
eax=001a1eb4
0:000> r eax=0
0:000> a eip
7c90120e add eax,0x100
7c901213
0:000> u eip
ntdll!DbgBreakPoint:
7c90120e 0500010000      add     eax,100h
7c901213 c3              ret
7c901214 8bff            mov     edi,edi
7c901216 8b442404        mov     eax,dword ptr [esp+4]
7c90121a cc              int     3
7c90121b c20400          ret     4
ntdll!NtCurrentTeb:
7c90121e 64a118000000    mov     eax,dword ptr fs:[00000018h]
7c901224 c3              ret
0:000> t
eax=00000100 ebx=7ffd6000 ecx=00000007 edx=00000080 esi=001a1f48 edi=001a1eb4
eip=7c901213 esp=0007fb20 ebp=0007fc94 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
ntdll!DbgUserBreakPoint+0x1:
7c901213 c3              ret
0:000>`

또한-IDA로 플레이하는 동안 Chris Eagle의 IDA Pro Book을 확인하십시오 (StackOverflow가 첫 번째 게시물에 대해 두 개 이상의 링크를 게시하는 것을 원하지 않기 때문에 연결 해제 됨). 거기에 가장 좋은 참조가 있습니다.


저는 최근에 컴퓨터 시스템 수업을 들었습니다. 주제 중 하나는 하드웨어와 통신하는 도구로서의 어셈블리였습니다.

For me, the knowledge of assembly wouldn't have been complete without understanding the details of how computer systems work. Understanding that, brings in an new understanding of why assembly instructions on one processor architecture is great but is terrible on another architecture.

Given this, I'm inclined to recommend my class text book:

Computer Systems:A programmer's perspective.

컴퓨터 시스템 : 프로그래머의 관점
(source: cmu.edu)

It does cover x86 assembly but the book is much more broad than that. It covers processor pipe-lining and memory as a cache, the virtual memory system and much more. All of this can affect how assembly could be optimized for the given features.


I think you want to learn the ASCII-ized opcode mnemonics (and their parameters), which are output by a disassembler and which are understood by (can be used as input to) an assembler.

Any assembler (e.g. MASM) would do.

And/or it might be better for you to read a book about it (there have been books recommended on SO, I don't remember which).


Are you doing other dev work on windows? On which IDE? If it's VS, then there's no need for an additional IDE just to read disassembled code: debug your app (or attach to an external app), then open the disassembly window (in the default settings, that's Alt+8). Step and watch memory/registers as you would through normal code. You might also want to keep a registers window open (Alt+5 by default).

Intel gives free manuals, that give both a survey of basic architecture (registers, processor units etc.) and a full instruction reference. As the architecture matures and is getting more complex, the 'basic architecture' manuals grow less and less readable. If you can get your hands on an older version, you'd probably have a better place to start (even P3 manuals - they explain better the same basic execution environment).

If you care to invest in a book, here is a nice introductory text. Search amazon for 'x86' and you'd get many others. You can get several other directions from another question here.

Finally, you can benefit quite a bit from reading some low-level blogs. These byte-size info bits work best for me, personally.


This will not necessarily help you write efficient code!

i86 op codes are more or less a "legacy" format that persists because of the sheer volume of code and executable binaries for Windows and Linux out there.

Its a bit like the old scholars writing in latin, an Italian speaker like Galileo would write in Latin and his paper could be understood by a Polish speaker like Copernicus. This was still the most effective way to communicate even though niether was particulary good at Latin, and Latin is a rubbish language for expressing mathematical ideas.

So compilers generate x86 code by default, and, modern chips read the anceint Op codes and transalate what they see into parallel risc instructions, with reordered execution, speculative execution, pipelining etc. plus they make full use of the 32 or 64 registers the processor actually has (as opposed to the pathetic 8 you see in x86 instructions.)

Now all optimising compilers know this is what really happens, so they code up sequences of OP codes which they know the chip can optimise efficiently -- even though some of these sequences would look innefficient to an circa 1990 .asm programmer.

At some point you need to accept that the 10s of thousands of man years effort compiler writers have put in have paid off, and, trust them.

The simplest and easiest way to get a more eficient runtime is to buy the Intel C/C++ compiler. They have a niche market for efficeint compilers, and, they have the advantage of being able to ask the chip designers about what goes on inside.


To do what you're wanting to do, I just took the Intel Instruction Set Reference (might not be the exact one I used, but it looks sufficient) and some simple programs I wrote in Visual Studio and started throwing them into IDAPro/Windbg. When I out-grew my own programs, the software at crackmes was helpful.

I'm assuming that you have some basic understanding of how programs execute on Windows. But really, for reading assembly, there's only a few instructions to learn and a few flavors of those instructions (e.g., there's a jump instruction, jump has a few flavors like jump-if-equal, jump-if-ecx-is-zero, etc). Once you learn the basic instructions it's pretty simple to get the gist of the program execution. IDA's graph view helps, and if you're tracing the program with Windbg, it's pretty simple to figure out what the instructions are doing if you're not sure.

After a bit of playing like that, I bought Hacker Disassembly Uncovered. Generally, I stay away from books with the word "Hacker" in the title, but I really liked how this one went really in-depth about how compiled code looked disassembled. He also goes into compiler optimizations and some efficiency stuff that was interesting.

It all really depends on how deeply you want to be able to understand the program, too. If you're reverse engineering a target looking for vulnerabilities, if you're writing exploit code, or analyzing packed malware for capabilities, you'll need more of a ramp-up time to really get things going (especially for the more advanced malware). On the other hand, if you just want to be able to change your character's level on your favorite video game, you should be doing fine in a relatively short amount of time.


One of the standard pedagogic assembly languages out there is MIPS. You can get MIPS simulators(spim) and various teaching materials for it.

Personally, I'm not a fan. I rather like IA32.


My personal favorite is NASM, mostly because it's multi-platform, and it compiles MMX, SSE, 64-bit...

I started compiling some simple C source file with gcc, and "trans-coding" the assembler instruction from gcc-format into NASM-format. Then you can change small portions of code, and verify the performance improvement it brings.

The NASM documentation is really complete, I never needed to search for information from books, or other sources.


Some links you might find useful to learn the assembly - source code mapping -

Assembly And The Art Of Debugging

Debugging – Modifying Code At Runtime

Hope you find these useful.


Lots of good answers here. Low-level programming, assembly etc are popular in the security community, so it is worthwhile looking for hints and tips there once you get going. They even have some good tutorials like this one on x86 assembly.


To actually reach your goal, you might consider starting with the IDE you are in. The generally is a disassembler window, so you can do single stepping through code. There is usually a view of some sort to let you see the registers and look into memory areas.

Examination of unoptimized c/c++ code will help build a link into the kind of code that the compiler generates for your sources. Some compilers have some sort of ASM reserved word which lets you insert machine instructions in your code.

My advice would be to play around with those sorts of tools for a while and get your feet wet, then step up? down? to straight assembler code on what ever platform you are running on.

There are a lot of great tools out there, but you might find it more fun, to avoid the steep learning curve at first.


We learned assembly with a microcontroller development kit (Motorola HC12) and a thick datasheet.


Off topic I know, but since you are a Windows programmer I can't help but think that it may be a more appropriate and/or better use of your time to learn MSIL. No, it's not assembly, but it's probably more relevant in this .NET era.


Knowing assembly can be useful for debugging but I wouldn't get too excited about using it for optimizing your code. Modern compilers are usually much better at optimizing that a human these days.


You can check out xorpd x86 Assembly video course. (I wrote it). The course itself is paid, but the exercises are open sourced, on github. If you have some programming experience I think you should be able to work just with the exercises and understand everything.

코드는 Windows 플랫폼 용이며 Fasm 어셈블러를 사용하여 작성되었습니다 . 코스와 연습 문제에는 높은 수준의 구성이 포함되어 있지 않지만 원하는 경우 Fasm을 사용하여 매우 복잡한 매크로를 만들 수 있습니다.

참고 URL : https://stackoverflow.com/questions/1360279/learning-assembly

반응형