위치로 진입 점

마지막 업데이트: 2022년 7월 13일 | 0개 댓글
  • 네이버 블로그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 트위터 공유하기
  • 카카오스토리 공유하기
Login 화면

모듈 내보내고 가져오기

이전 챕터에서는 export 와 import 의 기본적인 사용법을 알아보았는데, 이번 챕터에선 좀 더 다양한 사용법을 배워보겠습니다.

선언부 앞에 export 붙이기

변수나 함수, 클래스를 선언할 때 맨 앞에 export 를 붙이면 내보내기가 가능합니다.

아래 내보내기는 모두 유효합니다.

클래스나 함수 선언 시, 선언부 앞에 export 를 붙인다고 해서 함수 선언 방식이 함수 선언문에서 함수 표현식(function expression) 으로 바뀌지 않습니다. 내보내 지긴 했지만 여전히 함수 선언문입니다.

대부분의 자바스크립트 스타일 가이드는 함수나 클래스 선언 끝에 세미콜론을 붙이지 말라고 권유합니다.

같은 이유로 export class 나 export function 끝에 세미콜론을 붙이지 않습니다.

선언부와 떨어진 곳에 export 붙이기

선언부와 export 가 떨어져 있어도 내보내기가 가능합니다.

아래 예시에선 함수를 먼저 선언한 후, 마지막 줄에서 내보냅니다.

참고로 export 문을 함수 선언부 위에 적어주는 것도 동일하게 동작합니다.

import *

무언갈 가져오고 싶다면 아래와 같이 이에 대한 목록을 만들어 import <. >안에 적어주면 됩니다.

가져올 것이 많으면 import * as 처럼 객체 형태로 원하는 것들을 가지고 올 수 있습니다. 예시를 살펴보겠습니다.

이렇게 '한꺼번에 모든 걸 가져오는 방식’을 사용하면 코드가 짧아집니다. 그런데도 어떤 걸 가져올 땐 그 대상을 구체적으로 명시하는 게 좋습니다.

이렇게 하는 데는 몇 가지 이유가 있습니다.

웹팩(webpack)과 같은 모던 빌드 툴은 로딩 속도를 높이기 위해 모듈들을 한데 모으는 번들링과 최적화를 수행합니다. 이 과정에서 사용하지 않는 리소스가 삭제되기도 합니다.

아래와 같이 프로젝트에 서드파티 라이브러리인 say.js 를 도입하였다 가정합시다. 이 라이브러리엔 수 많은 함수가 있습니다.

현재로선 say.js 의 수 많은 함수 중 단 하나만 필요하기 때문에, 이 함수만 가져와 보겠습니다.

빌드 툴은 실제 사용되는 함수가 무엇인지 파악해, 그렇지 않은 함수는 최종 번들링 결과물에 포함하지 않습니다. 이 과정에서 불필요한 코드가 제거되기 때문에 빌드 결과물의 크기가 작아집니다. 이런 최적화 과정은 '가지치기(tree-shaking)'라고 불립니다.

어떤 걸 가지고 올지 명시하면 이름을 간결하게 써줄 수 있습니다. say.sayHi() 보다 sayHi() 가 더 간결하네요.

어디서 어떤 게 쓰이는지 명확하기 때문에 코드 구조를 파악하기가 쉬워 리팩토링이나 유지보수에 도움이 됩니다.

import ‘as’

as 를 사용하면 이름을 바꿔서 모듈을 가져올 수 있습니다.

sayHi 를 hi 로, sayBye 를 bye 로 이름을 바꿔서 가져와 봅시다.

Export 위치로 진입 점 ‘as’

export 에도 as 를 사용할 수 있습니다.

sayHi 와 sayBye 를 각각 hi 와 bye 로 이름을 바꿔 내보내 봅시다.

이제 다른 모듈에서 이 함수들을 가져올 때 이름은 hi 와 bye 가 됩니다.

export default

모듈은 크게 두 종류로 나뉩니다.

  1. 복수의 함수가 있는 라이브러리 형태의 모듈(위 예시의 say.js )
  2. 개체 하나만 선언되어있는 모듈(아래의 user.js . class User 하나만 내보내기 함)

대개는 두 번째 방식으로 모듈을 만드는 걸 선호하기 때문에 함수, 클래스, 변수 등의 개체는 전용 모듈 안에 구현됩니다.

그런데 이렇게 모듈을 만들다 보면 자연스레 파일 개수가 많아질 수밖에 없습니다. 그렇더라도 모듈 이름을 잘 지어주고, 폴더에 파일을 잘 나눠 프로젝트를 구성하면 코드 탐색이 어렵지 않으므로 이는 전혀 문제가 되지 않습니다.

모듈은 export default 라는 특별한 문법을 지원합니다. export default 를 사용하면 '해당 모듈엔 개체가 하나만 있다’는 사실을 명확히 나타낼 수 있습니다.

내보내고자 하는 개체 앞에 export default 를 붙여봅시다.

파일 하나엔 대개 export default 가 하나만 있습니다.

이렇게 default 를 붙여서 모듈을 내보내면 중괄호 <> 없이 모듈을 가져올 수 있습니다.

중괄호 없이 클래스를 가져오니 더 깔끔해 보이네요. 모듈을 막 배우기 시작한 사람은 중괄호를 빼먹는 실수를 자주 합니다. named export 한 모듈을 가져오려면 중괄호가 필요하고, default export 한 모듈을 가져오려면 중괄호가 필요하지 않다는 걸 기억해 실수를 방지합시다.

named export default export
export class User export default class User
import from . import User from .

사실 named export와 default export를 같은 모듈에서 동시에 사용해도 문제는 없습니다. 그런데 실무에선 이렇게 섞어 쓰는 사례가 흔치 않습니다. 한 파일엔 named export나 default export 둘 중 하나만 사용합니다.

파일당 최대 하나의 default export가 있을 수 있으므로 내보낼 개체엔 이름이 없어도 괜찮습니다.

아래 예시의 개체엔 이름이 없지만 모두 에러 없이 잘 동작합니다.

export default 는 파일당 하나만 있으므로 이 개체를 가져오기 하려는 모듈에선 중괄호 없이도 어떤 개체를 가지고 올지 정확히 알 수 있으므로 이름이 없어도 괜찮습니다.

default 를 붙이지 않았다면 개체에 이름이 없는 경우 에러가 발생합니다.

‘default’ name

default 키워드는 기본 내보내기를 참조하는 용도로 종종 사용됩니다.

함수를 내보낼 때 아래와 같이 함수 선언부와 떨어진 곳에서 default 키워드를 사용하면, 해당 함수를 기본 내보내기 할 수 있습니다.

흔치 않지만 user.js 라는 모듈에 ‘default’ export 하나와 다수의 named export가 있다고 해봅시다.

아래와 같은 방식을 사용하면 default export와 named 위치로 진입 점 export를 동시에 가져올 수 있습니다.

* 를 사용해 모든 것을 객체 형태로 가져오는 방법도 있는데, 이 경우엔 default 프로퍼티는 정확히 default export를 가리킵니다.

default export의 이름에 관한 규칙

named export는 내보냈을 때 사용한 이름 그대로 가져오므로 관련 정보를 파악하기 쉽습니다.

그런데 아래와 같이 내보내기 할 때 쓴 이름과 가져오기 할 때 쓸 이름이 동일해야 한다는 제약이 있죠.

named export와는 다르게 default export는 가져오기 할 때 개발자가 원하는 대로 이름을 지정해 줄 수 있습니다.

그런데 이렇게 자유롭게 이름을 짓다 보면 같은 걸 가져오는데도 이름이 달라 혼란의 여지가 생길 수 있습니다.

이런 문제를 예방하고 코드의 일관성을 유지하기 위해 default export 한 것을 가져올 땐 아래와 같이 파일 이름과 동일한 이름을 사용하도록 팀원끼리 내부 규칙을 정할 수 있습니다.

그런데 규칙이 있어도 이를 지키지 않는 사람이 있을 수 있기 때문에 어떤 팀은 named export만 사용할 것을 강제하는 경우도 있습니다. 모듈 하나에서 단 하나의 개체만 내보내는 경우에도 default 없이 이름을 붙여 내보내면 혼란을 방지할 수 있기 때문이죠.

이런 규칙은 아래에서 배울 모듈 다시 내보내기를 쉽게 해준다는 장점도 있습니다.

모듈 다시 내보내기

export . from . 문법을 사용하면 가져온 개체를 즉시 ‘다시 내보내기(re-export)’ 할 수 있습니다. 이름을 바꿔서 다시 내보낼 수 있는 것이죠. 예시를 살펴봅시다.

다시 내보내기가 왜 필요한건지 의문이 드실 겁니다. 유스 케이스를 통해 다시 내보내기가 실무에서 언제 사용되는지 알아봅시다.

NPM을 통해 외부에 공개할 '패키지(package)'를 만들고 있다고 가정합시다. 이 패키지는 수많은 모듈로 구성되어있는데, 몇몇 모듈은 외부에 공개할 기능을, 몇몇 모듈은 이러한 모듈을 도와주는 ‘헬퍼’ 역할을 담당하고 있다고 합시다.

패키지 구조는 아래와 같습니다.

진입점 역할을 하는 '주요 파일’인 auth/index.js 을 통해 기능을 외부에 노출시키면 이 패키지를 사용하는 개발자들은 아래와 같은 코드로 해당 기능을 사용할 겁니다.

이때 우리가 만든 패키지를 사용하는 외부 개발자가 패키지 안의 파일들을 뒤져 내부 구조를 건드리게 하면 안 됩니다. 그러려면 공개할 것만 auth/index.js 에 넣어 내보내기 하고 나머는 숨기는 게 좋겠죠.

이때 내보낼 기능을 패키지 전반에 분산하여 구현한 후, auth/index.js 에서 이 기능들을 가져오고 이를 다시 내보내면 원하는 바를 어느 정도 달성할 수 있습니다.

이제 외부 개발자들은 import from "auth/index.js" 로 우리가 만든 패키지를 이용할 수 있습니다.

export . from . 는 위와 같이 개체를 가지고 온 후 바로 내보낼 때 쓸 수 있는 문법입니다. 아래 예시는 위 예시와 동일하게 동작합니다.

default export 다시 내보내기

기본 내보내기를 다시 내보낼 때는 주의해야 할 점들이 있습니다.

user.js 내의 클래스 User 를 다시 내보내기 한다고 가정해 봅시다.

User 를 export User from './user.js' 로 다시 내보내기 할 때 문법 에러가 발생합니다. 어디가 잘못된 걸까요?

default export를 다시 내보내려면 위 예시처럼 export 를 사용해야 합니다.

export * from './user.js' 를 사용해 모든 걸 한 번에 다시 내보내면 default export는 무시되고, named export만 다시 내보내집니다.

두 가지를 동시에 다시 내보내고 싶다면 두 문을 동시에 사용해야 합니다.

default export를 다시 내보낼 땐 이런 특이한 상황도 인지하고 있다가 처리해줘야 하므로 몇몇 개발자들은 default export를 다시 내보내는것을 선호하지 않습니다.

지금까지 배운 export 타입을 다시 한번 살펴봅시다.

아래 타입들을 쭉 보고 얼마나 기억하는지 체크해 보세요.

  • 클래스, 함수 등의 선언부 앞에 export 붙여서 내보내기:
    • export [default] class/function/variable .
    • export .
    • export from "module"
    • export * from "module" (default export는 다시 내보내 지지 않음)
    • export from "module" (default export를 다시 내보냄)

    가져오기 타입 역시 정리해 봅시다.

    • named export 가져오기:
      • import from "mod"
      • import x from "mod"
      • import from "mod"
      • import * as obj from "mod"
      • import "mod"

      import/export 문은 스크립트의 맨 위나 맨 아래에 올 수 있는데 이 둘엔 차이가 없습니다.

      따라서 아래 스크립트는 문제없이 잘 동작합니다.

      대개는 편의상 스크립트 맨 위에 import 문을 위치시킵니다.

      import/export 문은 블록 <. >안에선 동작하지 않는다는 점에 유의하시길 바랍니다.

      조건을 충족하면 모듈을 가져오려는 의도로 작성된 아래 코드는 동작하지 않습니다.

      그런데 애플리케이션을 작성하다 보면 조건에 따라 모듈을 가져와야 하거나 어떤 특정 시점에 모듈을 불러와야 하는 경우가 생깁니다. 이럴 땐 어떤 방법을 사용해야 할까요? 요청이 있을 때만 모듈을 불러오는 게 가능할까요?

      Outwell Hartsdale 4PA Tent

      창문이 많은 Hartsdale 4PA는 다목적이며 밝고 통풍이 잘되는 터널 텐트로 어두운 2 개의 프리미어 침실 4 개에서 잠을 자고 있습니다. 그것의 날개 라운지 지역은 골방 좌석, 여분의 저장 공간 또는 아늑한 키즈 덴으로 사용될 수 있기 때문에 더 많은 유연성을 제공합니다. 수직 전면 벽의 깊은 캐노피는 태양과 비로부터 완전한 보호소와 유용한 추가 저장 공간을 제공합니다.
      풍모:
      향상된 내부 및 외부 생활 공간을위한 캐노피가있는 수직 전면 벽
      다목적 윙 라운지 공간은 여분의 생활 또는 수면 공간을 제공하거나 편안한 휴식 공간을 제공합니다.
      편안한 수면을위한 메시 환기 기능이있는 다크 프리미어 침실
      유연한 액세스를위한 추가 측면 도어
      곤충이없는 환기 옵션을 위해 전체 메쉬 패널로 뒷받침되는 이중 지퍼
      마그네틱 클로저가있는 빠르고 조용한 내부 도어
      내구성이 뛰어나고 방수 처리되며 폴리에틸렌 접지 시트로 꿰매어 짐
      플라이 시트 및 내부 기능 케이블 진입 점
      가볍고 따뜻한 톤의 플라이 시트 지붕이 밝고 활기 넘치는 내부 분위기를 만듭니다.
      피칭 유연성을위한 조정 가능한 페깅 포인트
      조명 및 품목을 최대 1.5kg까지 다양하게 배치 위치로 진입 점 할 수있는 HookTrack 시스템
      플라이 시트 외부에 편리하게 배치 된 안정적이고 작동하기 쉬운 팽창 / 수축 밸브
      편리함과 빠른 투구를위한 사전 부착 된 야광
      내부 텐트의 메쉬 포켓은 작은 물품을 안전하고 편리하게 보관합니다
      모든 스트레스 지점의 보강 패치
      후방 환기 시스템은 내부 온도 및 신선한 공기 흐름을 조절할 수있는 유연한 옵션을 제공합니다.
      눈부심을 줄이고 프라이버시를 보장하는 대형 착색 창
      요소로부터 최대한의 보호를위한 완벽한 이음새 밀봉 플라이 시트
      Outwell Easy Pegging System의 색상 코딩을 통해 캠프 참가자는 처음부터 올바른 위치에 페그를 사용하여 빠른 피칭과 안정적인 안정성을 제공합니다.
      컴팩트 한 팩 크기의 압축 가능한 캐리 백
      Outtex® 4000 선택 :
      Outtex® 4000 Select는 일반적인 일반 캠핑에 이상적인 원단에 대한 주요 기대치를 충족시키는 내구성이 뛰어난 품질의 100 % 폴리 에스터입니다. 난연제이며 4,000mm 정수압 헤드 방수 등급을 제공하는 PU 코팅
      난연제 :
      재료는 텐트 위치로 진입 점 재료에 대한 모든 최신 규정을 충족합니다
      테이핑 솔기 :
      모든 이음새에 대한 추가 보호 기능, 테이프로 물이 침투 할 가능성이 없습니다
      공기 역학 폭풍 방지 9 :
      숨겨진 기둥이있는 텐트의 공기 역학적 디자인은 모든 텐트가 날씨에 관계없이 안정적임을 보장합니다.
      Outwell 엄밀한 공기 시스템 :
      쉽게 접근 할 수있는 외부 밸브를 통해 개별적으로 팽창 및 수축되는 개별 튜브가 특징입니다.
      Outwell Wind Brace 시스템 :
      Outwell Wind Brace System은 바람이 부는 조건에서 안정성을 높이기 위해 에어 튜브를 따라 주요 위치에서지지 웨빙을 사용합니다.
      지상 시스템에서 꿰매어 짐 :
      지면에 봉인 된 것이 텐트에서 흘림, 곤충, 먼지 및 물을 막는 가장 좋은 방법입니다. 지표가 텐트의 필수 부분 인 경우 지상에서 위쪽으로 모든 날씨를 보호합니다.
      메시가있는 Outwell Easy Access System :
      메인 도어와 메쉬가 한쪽으로 접 히고 접지 시트가지면과 수평이되어 안전하고 쉽게 접근 할 수 있습니다.
      프리미어 침실 :
      편안한 침실은 벤치마킹 공간을 제공하며 높이는 최소 215cm입니다.
      어두운 내부 :
      어두운 지붕 패널과 측면은 빛의 침투를 줄여 수면 품질을 향상시킵니다.
      빠르고 조용한 내부 도어 :
      내부 도어의 수직 이음새에 꿰매는 마그네틱 스트립은 빠르고 조용한 침실 출입을 가능하게하며 필요할 때보다 안전한 폐쇄를 위해 지퍼 옵션으로 빠져 나갈 수 있습니다.
      Outwell HookTrack 시스템 :
      전략적으로 배치 된 트랙을 사용하면 케이블을 연결하고 경량 액세서리를 부착 할 수있는 특수 고리를 배치 할 수 있습니다
      케이블 진입 점 :
      메인 리드를 텐트로 안전하게 통과시킬 수있는 지퍼 섹션
      드라이 짚 :
      테이핑 된 지퍼 솔기는 방수 성능을 보장합니다
      에어 펌프 포함 :
      모든 에어 튜브 기술 텐트와 함께 제공되는 부착이 쉽고 고효율 수동 에어 펌프는 팽창 식 텐트를 팽창시키는 짧은 작업을합니다.
      수면 컴포트 3 명 :
      업계 표준으로 각 침실에서 1 인당 60cm를 허용하는 안락한 수면 등급으로 텐트를 정의하고 있으며 이것이 충분하지 않다는 것을 알고 있으며 에어 베드의 출현으로 Outwell 수면의 편안함은 1 인당 70 80cm로 결정했습니다.
      Outwell Guyline 리테이너 시스템 :
      간단하고 효과적이며 영감을 얻은이 기능은 야영자가 포장을 풀 때 골칫거리를 피할 수 있도록합니다.
      커튼 전환 :
      각 창에 고정 장치가있는 커튼으로 필요한만큼 일광을 적게 받도록합니다.
      착색 윈도우 :
      두 가지 주요 기능을 제공하는 착색 코팅이 된 창문; 텐트에서 태양의 눈부심과 개인 정보 보호.
      교수형 시스템 :
      강도와 보안을 위해 텐트에 테이프로 고정 된 서스펜션 포인트를 통해 토글로 내부를 부착
      명세서:
      플라이 시트 : Outtex® 4000 Select, 100 % 폴리 에스테르
      정수압 헤드 : 4000 mm
      잠 : 4
      폴란드 건축 : 팽창 식 / 강철
      튜브 : 최고의 성능을위한 견고한 에어 시스템 프레임
      최대 압력 : 9 psi / 0.6 bar
      기둥 : 강철 기둥 19 mm
      내성 : 통기성 폴리 에스테르, 100 % 폴리 에스테르
      바닥 : 이중 코팅 방수 폴리에틸렌, 100 % 폴리에틸렌
      포장 크기 : 86 x 43 x 43 cm
      무게 : 25,4 kg

      이제 Outwell Hartsdale 4PA Tent 제품의 다양한 사양을 체험하실 수 있습니다. trekkinn에서 제품을 구입하시고 다양한 위치로 진입 점 혜택을 누리세요. Outwell Hartsdale 4PA TentOutwell에서 품질을 보증합니다. 다른 제품이 필요하시다면 우리 스토어의 텐트 카탈로그나 텐트 제품군을 보시면 좋습니다.

      컴퓨팅에서 진입 점이 무엇입니까?

      컴퓨터에서 진입 점은 코드가 시작되는 프로그램, 모듈 또는 기능의 지점입니다. 특히 메모리 주소가 시작되는 위치입니다. 프로그램에서 이는 첫 번째 코드 모듈이거나 실행되는 첫 번째 코드 행입니다. BASIC 또는 COBOL과 같이 선형 인 프로그램에서 진입 점은 문자 그대로 첫 번째 코드 행입니다. 그런 다음 코드는 일종의 점프 또는 호출이 실행될 때까지 순차적으로 따릅니다. C 프로그래밍 언어의 모든 변형과 같은 모듈 식 프로그래밍에서 시작점은 시작 모듈입니다. C에서 이것은“Main ()”함수입니다.

      이전 프로그램 및 운영 체제에서는 실행중인 기능 또는 시스템에 따라 프로그램에 여러 개의 진입 점이있을 수 있습니다. Windows® 및 Unix를 포함한 대부분의 최신 운영 체제에서 프로그램은 단일 진입 점을 지원하는 언어로 작성됩니다. 현대 컴퓨팅의 초기에도 BASIC과 같은 언어는 프로그램에 대한 단일 진입 점을 가지면서 프로그램이 한 모듈에서 다른 모듈의 진입 점으로 무차별 적으로 "점프"할 수있는 "긴 점프"를 지원할 수 있습니다. 이것은“스파게티 코드 (spoetti code)”라고 불리우며, 유지하거나 수정하기가 어렵다.

      진입 점은 프로그램의 진입 점을 참조하지 않을 수도 있지만 다른 프로그램과 공유되는 일종의 미니 프로그램 인 동적 링크 라이브러리 (DLL)의 진입 점일 수 있습니다. 키보드 입력을 제어하는 ​​DLL이 한 예입니다. 프로그램, 모듈 또는 기능의 유형에 관계없이 진입 점은 해당 코드에서 처리되는 단일 지점입니다. 언어를 이해하거나 프로그램을 수정하고 지원하는 핵심은 해당 특정 프로그램이나 운영 체제에서 진입 점이 어떻게 식별되는지 이해하는 것입니다.

      진입 점 개념은 컴퓨터 프로그래밍이 초기의 완전히 선형적인 방법을 떠날 때 구현되었습니다. 당시 컴퓨터 프로그램은 위치로 진입 점 첫 번째 코드 줄에서 시작하여 한 번에 한 줄씩 진행하여 프로세스가 끝났습니다. 곧 루핑, 조건부 분기, 재귀 등과 같은 프로그래밍 구조는 기능적으로 더 효율적인 프로그램을 만들었지 만 코드 내에서 처리가 튀어 나왔습니다. 이러한 프로그램의 특성상 처리가 실제로 시작되기 전에 많은 위치로 진입 점 코드 행 또는 섹션이있을 수 있습니다. 이러한 이유로 진입 점이 작성 및 식별되었습니다.

      C에서는 이것이 main () 함수가되었습니다. 코드에서이 함수가 존재하는 위치에 관계없이 처리가 시작된 위치입니다. 다른 언어에서는 진입 점이 위치와 위치가 아닌 위치에 의해 식별되지 않습니다. 프로그램의 시작 부분에는 변수 선언 및 서브 루틴 섹션이 포함될 수 있습니다. 이러한 영역이나 기능을 따르는 첫 번째 코드 줄은 기본적으로 진입 점이됩니다.

      몇 해 전부터 상당수의 악성코드들은 실행압축이라는 형태를 사용해서 안티바이러스 프로그램으로부터 자신을 보호하고 있습니다.이번 보안칼럼에서는 실행압축이 어떤 원리로 악성코드 파일들을 보호해주는 것인지에 대해서 알아보겠습니다.

      1. 실행압축이란?
      우리가 보통 압축파일이라고 부르는 것들은 문서파일이나 영화파일, 실행파일 등을 하나 이상의 파일로 묶어주면서 용량을 축소해주는 형태였습니다. 실행압축도 파일을 압축한다는 점에서는 일반적인 압축파일과 다를 바가 없습니다. 하지만 일반압축파일과 가장 구별되는 점은 그 대상이 실행파일이라는 점과 사용자가 직접 압축을 풀어주는 절차가 없다는 점입니다. 말 그대로 ‘압축이 된 상태로 실행이 가능한 파일 ’ 로 이해하시면 됩니다. 원래 이 실행압축이라는 형태는 까마득한 옛날 DOS OS를 주로 사용하던 시절에 부족한 보조기억장치(HDD,FDD)공간을 조금이나마 더 확보하기 위한 목적으로 사용되었습니다. 당시 HDD의 용량은 수십~수백 MB(메가바이트)였으니 디스크가 부족해서 ZIP이나 ARJ 같은 데이터 압축프로그램으로 압축해두고 사용하던 실행파일들을 직접 풀어서 실행하지 않아도 되는 실행압축은 상당한 매력이 있었습니다. 물론, 하드디스크 용량의 단위가 TB(테라바이트)로 바뀌고 실행파일보다는 다른 멀티미디어파일들의 용량이 압도적으로 커져버린 현재에 와서는 그 용도가 상당히 변경이 되었습니다. 이런 실행압축을 가능하게 해주려면 ZIP이나 RAR 같은 압축프로그램이 있듯이 실행압축을 해주는 프로그램들이 있겠죠? 우리가 이번에 함께 살펴볼 실행압축 프로그램은 UPX입니다. UPX는 현재 가장 널리 사용되고 있는 실행압축 프로그램 중 하나입니다.

      2. 실행압축의 원리
      일반적으로 우리 컴퓨터에 .exe, .dll, .sys 등의 확장자를 가지고 있는 실행파일들은 컴퓨터만 알 수 있는 기계어의 덩어리입니다. OS가 여러가지가 있고 OS마다 실행파일들이 틀리듯이 실행압축도 이런 플랫폼에 대해서 의존성을 갖고 있습니다. 이번 시간에 우리는 윈도우즈 OS를 기반으로 하는 실행파일인 PE(Portable Executable)파일을 대상으로 실행압축의 원리에 대해서 알아보겠습니다. Microsoft사에서 PE파일이라고 명명한 이 실행파일들은 일정한 포멧을 가지고 있으며 이 포멧은 바로 실행압축이 가능케 하는 중요한 요소 중 하나입니다. 그러므로 실행압축을 원리를 알기 위해서는 먼저 윈도우즈 OS의 실행파일은 PE파일의 구조에 대해서 간단히 알고 있어야 합니다.


      [그림 1] 압축되지 않은 PE파일의 구조

      [그림 1]에서는 윈도우즈 기반의 32비트 실행파일인 PE파일을 PE포멧을 볼 수 있는 프로그램을 이용해서 열어보았습니다. 우리가 어떤 프로그램을 실행하게 되면 윈도우즈는 먼저 이 파일의 실행에 필요한 자원을 확보하게 됩니다. 지금 메모리가 부족하지는 않은지? 이 파일을 이 시스템에서 정상적으로 실행할 수 있는지? 혹시 파일이 손상되지는 않았는지도 검사하겠죠. 모든 준비를 마치면 윈도우즈는 [그림 1]에서 보이는 [Address of Entry Point]에 기록된 위치로 제어를 넘기게 됩니다. ‘이제 난 너를 실행할 모든 준비를 마쳤으니 프로그램 너가 하고 싶은 일을 하라’ 는 거죠. [Address of Entry Point]는 엔트리포인트(EntryPoint)라고 불리며 이 파일의 코드가 실행되기 시작하는 진입점을 의미합니다. 우리가 실행한 프로그램들은 이 위치를 시작으로 진행이 되게 됩니다. [그림 1]에서 보이는 섹션(SECTION)이라는 부분들에는 실제로 이 프로그램이 실행되는 데 필요한 내용이 담겨있습니다. 각각의 섹션은 실행코드를 담고 있기도 하고 이 프로그램이 화면에 보여줘야할 그림이나 문자열, 숫자등의 정보를 담고 있기도 합니다. 엔트리포인트도 바로 저 섹션들 중 하나의 특정한 위치를 가리키고 있습니다. 섹션들은 실행파일이 차지하는 용량의 대부분을 차지하고 있습니다. 섹션에 포함되지 않은 부분들은 이 프로그램이 실행되는데 필요한 정보들만을 담고 있으며 섹션에 비해서 매우 작은 용량만을 차지하고 있습니다. 그렇다면 이제 실행압축이라는 녀석이 어디를 압축하는지는 눈치를 채셨을 것 같습니다. 실행압축 프로그램들은 주로 저 섹션들을 압축대상으로 삼습니다. 그런데 여기서 의문점이 생깁니다. 저 섹션들을 압축하게 되면 [Address of Entry Point]가 가리키는 위치도 함께 압축이 되어버리는데 이렇게 되면 프로그램을 정상적으로 시작할 수가 없게 됩니다. 그럼 어떻게 실행압축은 프로그램을 정상적으로 실행시킬 수 있는 걸까요? 이 부분을 이해하려면 PE파일을 구성하고 있는 섹션이라는 덩어리들을 조금 알아봐야 합니다.


      [그림 2] 위치로 진입 점 섹션에 명시된 특성

      PE포멧은 보다 효율적인 실행구조를 갖추기 위해서 각각의 섹션들을 용도에 따라서 구분하고 있으며 그 정보는 [그림 2]의 섹션헤더(Section Header)에 저장되어 있습니다. 섹션헤더는 섹션의 파일에서의 위치와 실제 실행이 된 상태에서의 위치정보를 담고 있으며 섹션 각각의 용도에 따라서 특성(위치로 진입 점 Characteristics)을 설정해두고 있습니다. 예를 들어서 프로그램의 아이콘이나 그림파일이 들어 있는 섹션은 [.rsrc] 라는 부분입니다. Resource의 줄임말이죠. 일반적인 프로그램은 그림이나 아이콘 같은 내용은 그냥 읽어올 수만 있으면 충분합니다. 실행이 되야 하는 코드가 아니므로 실행 특성을 부여할 필요도 없습니다. 그래서 [.위치로 진입 점 rsrc] 같은 섹션은 주로 읽을 수 있는 특성으로 정의하게 됩니다. [.text] 라고 이름지어진 섹션은 프로그램들이 실제로 수행하는 코드들이 담겨 있습니다. 실행파일의 코드는 기계어들의 집합이니 눈으로 봐서는 알기 힘든 내용으로 가득차 있겠죠? 물론 이런 코드가 들어있는 섹션은 실행이 가능해야겠죠? 그래서 [그림 2]에서 볼 수 있듯이 코드섹션인 [.text]섹션에는 IMAGE_SCN_MEM_READ와 함께 IMAGE_SCN_MEM_EXECUTE이라는 특성을 부여했습니다. 이 섹션은 읽을 수 있고 실행도 가능하다는 의미 정도로 이해하시면 됩니다. PE포멧에는 이렇게 각 섹션별로 할 수 있는 일들이 정의되어있습니다. 이 정도만 알면 실행압축을 이해하기 위한 PE파일에 대한 공부는 충분합니다. 이제부터는 실행압축프로그램 UPX를 통해서 실행파일을 압축하면 어떻게 이 파일의 압축이 자동으로 해제되고 실행까지도 가능하게 되는지 알아보겠습니다.


      [그림 3] 압축되기 전의 실행파일(1,297,408 바이트)의 진입점

      [그림 2]는 제 컴퓨터에 있는 압축되지 않은 실행파일을 올리디버거라는 프로그램으로 열어본 모습입니다. 진입점의 코드를 볼 수 있습니다.


      [그림 4] 압축된 후의 실행파일(271,872 바이트)의 진입점

      [그림 3]은 [그림 2]의 실행파일을 UPX 프로그램으로 압축한 후의 모습니다. 물론 정상적으로 실행이 됩니다. 실행압축을 하기 전에는 1,297,408바이트(Byte)의 사이즈를 가지던 실행파일이 271,872바이트로 1/5에 가까운 크기의 파일로 줄어들었습니다. 또한 진입점의 주소(위치)와 실제코드도 변경이 되었습니다. 파일의 사이즈는 우리가 사용하는 ZIP, RAR등의 일반적인 압축프로그램으로 압축을 해도 줄어들 수 있으니 별로 신기한 부분은 아닙니다. 하지만 어떻게 압축되어 있는 코드를 실행을 할 수 있었던 걸까요? 비밀은 [그림 3]에 보이는 코드에 있습니다. 압축 후에 변경된 실행파일의 구조를 보면서 한번 알아보겠습니다.


      [그림 5] 압축된 후의 PE파일의 구조

      [그림 5]에서는 압축된 후의 PE파일의 구조를 볼 수 있습니다 [그림 1]의 압축되기 전의 PE파일의 구조와 위치로 진입 점 비교해보면 프로그램의 진입점인 [Address Of Entry Point]의 값이 변경되었음을 알 수 있습니다. 여기에 압축 전에는 6개를 가지고 있던 섹션이 3개로 줄어들었습니다. 앞의 내용에서 섹션들은 특성에 따라서 나뉘어져있다고 했는데 이렇게 섹션을 줄여버리면 문제가 없을까요? 네, 특별히 문제될 것은 없습니다. 다만 이 프로그램의 아이콘이나 버전정보가 들어있는 [.rsrc]섹션을 압축해버리면 파일상태에서 우리는 이 파일의 버전이나 아이콘을 볼 수 가 없겠죠? 그래서 [.rsrc]섹션은 압축을 하지 않은 형태로 남아있도록 했습니다. UPX라는 실행압축프로그램은 이렇게 여러개의 섹션들을 압축을한 다음 하나로 통합합니다. 여러 개로 나뉘어져있던 섹션은 [UPX1]이라는 섹션에 압축된 형태로 통합되어 있습니다. 그럼 저 압축된 내용은 누가 압축을 해제해주는 걸까요? 앞에서 모든 프로그램은 진입점에서부터 실행이 시작이 된다고 했습니다. [그림 3]에서 우리는 압축된 후에 이 프로그램의 진입점의 내용이 압축되기 전과 완전히 내용이 틀려진 것을 발견할 수 있습니다. 그럼 저 변경된 코드는 무엇을 위한 것일까요? 여러분이 예상하셨듯이 저 부분이 바로 UPX1섹션에 압축되어 있는 섹션들의 압축을 해제해주는 코드입니다.


      [그림 6] 압축 전과 후의 섹션의 변화

      [그림 6] 에서는 압축 전후 섹션의 변화를 보여줍니다. 여러개로 나뉘어져 있던 섹션들이 .rsrc 섹션을 제외하고는 모두 UPX1섹션안에 압축되어 있습니다. 압축 전에는 .text 섹션을 가리키고 있던 진입점도 UPX1의 [압축해제코드]의 위치를 가리키고 있습니다. 저 압축해제코드는 압축된 섹션들을 원래의 위치에 풀어주게 됩니다. 파일형태에서는 어떤 곳에 있어도 상관없었던 코드들이지만 실행이 된 상태에서는 원래의 위치로 올바르게 위치해 있어야 하므로 압축해제코드에서는 압축된 내용을 UPX1섹션에서 읽어와서 압축을 해제한 다음 원래의 위치로 복구해주고 압축으로 인해서 제대로 수행되지 못했던 작업까지 모두 수행한 다음에 원래의 진입점으로 코드의 제어권을 넘겨주게 됩니다.


      [그림 7] 모든 작업을 수행하한 후에 원래의 진입점으로 제어를 넘겨주는 코드

      [그림 7]은 압축해제코드의 맨 마지막에 수행되는 는 코드입니다. 위에서 설명한 모든 작업을 수행한 후에 원래의 진입점으로 제어를 넘겨주는 부분이죠. [JMP 00401210] 이라는 코드에서 [그림 8]에서 본 원래 코드의 진입점과 동일한 위치로 제어를 넘겨줌을 알 수 있습니다. 그런데 앞에서 섹션에는 각각의 목적에 따라서 특성이 있다고 했습니다.


      [그림 8] 압축하기 전의 섹션의 Characteristics

      [그림 8]에서는 압축되기 전의 섹션의 Characteristics를 볼 수 있습니다. .text 섹션의 내용은 실행과 읽기가 가능함을 알 수 있습니다.


      [그림 9] 압축된 후의 섹션의 Characteristics

      [그림 9]에서는 압축된 후의 섹션의 Characteristics를 볼 수 있습니다. [그림 8]에 비해서 추가된 부분이 보이실 겁니다. 바로 IMAGE_SCN_MEM_WRITE입니다. 그럼 이 섹션은 [.text]섹션과 틀리게 쓰기를 할 수 있겠죠? 맨 처음에 위치한 UPX0섹션은 사실 아무런 내용이 없는 빈 섹션입니다. 이 섹션은 압축을 해제한 후의 내용을 옮기기 위한 섹션입니다. 그래서 [.text]섹션의 프로세스 이미지 상에서의 주소를 그대로 갖고 있으면서 IMAGE_SCN_MEM_WRITE 특성이 추가된 것입니다. 만약 UPX0섹션의 Characteristics에 IMAGE_SCN_MEM_WRITE 특성이 없다면 이 프로그램은 실행되고 나서 [그림 4]의 코드가 압축을 풀어서 원래의 코드위치인 UPX0로 옮기려고 시도하는 순간 종료되어버릴 것입니다. 섹션의 특성에 위반되는 행위를 위치로 진입 점 했기 때문이죠. 실행압축을 실제로 구현하기 위해서는 사실 위에서 설명한 것보다 훨씬 많은 부분을 고려를 해야 합니다. 하지만 우리는 원리를 이해하기 위함이 목적이므로 여기서 실행압축의 원리에 대한 설명은 마치도록 하겠습니다.

      3. 악성파일이 사용하는 실행압축의 의미
      지금까지 실행압축이 압축된 실행파일을 어떻게 동작시기는지에 대해서 간략하게나마 알아보았습니다. 그렇다면 악성파일은 왜 실행압축을 한 상태로 배포가 되는 것일까요? 위에서 설명했듯이 보조기억장치용량의 증가로 실행압축은 이제 압축으로서의 의미는 퇴색되었습니다. 오히려 저런 압축을 해제하는 코드와 그에 따른 연산으로 시스템의 자원을 잡아먹게 되므로 실행속도는 미미하게나마 느려지게 됩니다. 현재의 실행압축의 목적은 실행파일의 보호가 주목적입니다. 파일용량의 축소라는 기능은 부수적인 기능으로 전락했습니다. 그렇다면 어떻게 안티바이러스 프로그램들을 우회할 수 있는 것일까요? 이 부분은 안티바이러스 프로그램의 악성파일 진단기법 중 하나와 관련이 있습니다. 안티바이러스 프로그램의 악성파일 진단기법에는 여러가지가 있지만 가장 오래되고 범용적인 기법은 바로 파일의 특정위치의 내용을 데이터베이스화한 다음 검사 대상이 되는 파일과 비교하는 방식입니다. 그런데 이 때 파일의 특정위치는 실행압축 프로그램이 변경하는 부분과 일치하는 경우가 많습니다. 실행압축을 하게 되면 안티바이러스 프로그램이 진단하는 위치의 내용 또한 변경되기 때문에 이런 진단방식으로는 실행압축이 된 파일은 진단을 할 수 없게 되는 것입니다. 하나의 악성파일을 수십가지의 실행압축을 사용해서 압축한 후에 배포하면 네트워크를 통해서 전파되는 최근의 추세에서 배포될 파일의 사이즈를 줄일 수 있다는 점 외에도 위에서 설명드린 진단방식에 대해서는 수십가지의 악성파일을 작성한 것과 비슷한 효과를 누릴 수 있다는 점에서 악성파일 제작자들에게 실행압축은 큰 매력이 있습니다. 상당수의 악성파일들은 실행압축의 이런 특성을 이용하여 자기자신을 보호하고 있습니다. 그래서 현재의 주요 안티바이러스 프로그램들은 이런 실행압축을 해제하는 기능을 추가했습니다. 하지만 한가지 종류의 실행압축파일을 해제하기 위한 기술을 개발하는데 긴 시간이 소요되고 사용자 입장에서는 이를 진단하기 위해서 시스템의 자원을 많이 소모해야 한다는 점을 생각하면 앞으로도 실행압축의 인기는 당분간 지속될 것으로 보입니다.


      (주)하우리 개발센터 엔진기술팀 손성민 주임연구원

      네오가 필요해

      [Android] Entry point(시작점, 진입점) 변경(Launcher, Main) 하기

      • Steele Spiegel
      • Android/Android Dev
      • 2022. 4. 24.

      진입점(Entry point)

      일반적으로 프로그램들은 시작점(진입점)이라는 것이 존재합니다. 자바의 경우, main() 메소드로 진입을 하며 진입은 한개로 이루어지는 것이 보편적이지만, 안드로이드의 경우 단일 진입점 혹은 시작점이라는 것이 존재하지 않고, 4가지의 컴포넌트가 이를 대체합니다.

      AndroidManifest.xml

      AndroidManifest.xml

      위 화면은 AndroidManifest.xml 화면이며 이제 막 만든 프로젝트를 열어본 것입니다. Activity는 MainActivity밖에 없기 때문에 단일 시작점은 MainActivity가 됩니다.

      현재 이 프로젝트를 실행하면, 아래와 같이 기본으로 제공하는 Hello World! 화면이 뜨게 될 것입니다.

      Hello World 화면

      여기서 새로운 Activity를 추가해보도록 하겠습니다.

      Login Activity 추가

      전혀 위치로 진입 점 다른 액티비티 화면을 보여주기 위해 Login Activity를 추가하였습니다.

      최종적으로 Finish를 눌러, LoginActivity를 생성하게 되면, 이제 안드로이드에서 로그인을 할 수 있는 액티비티와 로그인 기능에 도움이 되는 코드, layout 등이 추가 됩니다.

      로그인 기능들이 추가된 모습

      이제 이 로그인을 메인으로 잡아보도록 위치로 진입 점 하겠습니다.

      추가된 Activity

      위 내용은 AndroidManifest.xml에서 Acvitiy 부분만 가져온 것입니다. 기존에는 MainActivity밖에 없었지만, 상단에 LoginActivity가 추가된 것을 볼 수 있습니다.

      MainActivity를 보면, intent-filter라는 것이 추가로 지정이 되어 있는데 이 영역으로 Entry Point를 변경할 수 있습니다.

      Main과 Launcher 변경

      위와 같이 intent-filter를 LoginActivity 영역으로 변경을 한 후, 프로그램을 다시 실행시켜보았습니다.

      진입점이 변경된 모습

      Login 화면

      변경을 하니 위와 같이 로그인 화면이 처음에 등장하는 것을 확인할 수 있습니다. 이처럼 Entry Point를 변경하기 위해서는 AndroidManifest.xml에서 intent-filter를 변경해주면 쉽게 변경이 된다는 것을 알 수 있습니다.


0 개 댓글

답장을 남겨주세요