ELF 포맷(The ELF Format) (tistory.com)

 

ELF 포맷(The ELF Format)

Executable HeaderSection HeadersSectionsProgram HeadersLazy Binding참고 및 인용리눅스 기반 시스템의 기본 바이너리 형식인 ELF(Executable and Linkable Format)을 살펴보자.ELF는 실행 가능한 바이너리 파일, 목적 파일,

rond-o.tistory.com

 

리눅스 기반 시스템의 기본 바이너리 형식인 ELF(Executable and Linkable Format)을 살펴보자.

ELF는 실행 가능한 바이너리 파일, 목적 파일, 공유 라이브러리, 코어 덤프 등에서 사용되는 형식이다. 여기서는 64비트의 실행 가능한 바이너리 파일을 중심으로 살펴보겠다.

  • A 64-bit ELF binary at a glance

ELF 바이너리는 ELF 파일 헤더, 프로그램 헤더, 그리고 섹션들과 섹션 헤더들로 이루어져 있다.

Executable Header

모든 ELF 파일은 executable header로 시작하며, /usr/include/elf.h에서 확인할 수 있다.

  • /usr/include/elf.h의 Elf64_Ehdr 정의
typedef struct {
  unsigned char	e_ident[EI_NIDENT];  /* Magic number and other info */
  Elf64_Half	e_type;         /* Object file type */
  Elf64_Half	e_machine;      /* Architecture */
  Elf64_Word	e_version;      /* Object file version */
  Elf64_Addr	e_entry;        /* Entry point virtual address */
  Elf64_Off	  e_phoff;        /* Program header table file offset */
  Elf64_Off	  e_shoff;        /* Section header table file offset */
  Elf64_Word	e_flags;        /* Processor-specific flags */
  Elf64_Half	e_ehsize;       /* ELF header size in bytes */
  Elf64_Half	e_phentsize;    /* Program header table entry size */
  Elf64_Half	e_phnum;        /* Program header table entry count */
  Elf64_Half	e_shentsize;    /* Section header table entry size */
  Elf64_Half	e_shnum;        /* Section header table entry count */
  Elf64_Half	e_shstrndx;     /* Section header string table index */
} Elf64_Ehdr;

Elf64_Ehdr 구조체의 각 원소들의 자료형인 Elf64_Half, Elf64_Word 등은 uint16_t와 uint32_t다.

  • ELF 파일 헤더의 각 필드




    •  
    •  
    •  
    •  

    •  

    •  

    •  
    •  
    •  
    •  
    •  
    •  

Section Headers

ELF 바이너리의 코드와 데이터는 섹션(section)으로 나누어져 있다.

섹션의 구조는 각 섹션의 내용이 구성된 방식에 따라 다른데, 각 섹션 헤더(section header)에서 그 속성을 찾을 수 있다. 바이너리 내부의 모든 섹션에 대한 헤더 정보는 섹션 헤더 테이블(section header table)에서 찾을 수 있다.

섹션은 링커가 바이너리를 해석할 때 편리한 단위로 나눈 것이다.

링킹이 수반되지 않은 경우에는 섹션 헤더 테이블이 필요하지 않다. 만약 섹션 헤더 테이블 정보가 없다면 e_shoff 필드는 0이다.

바이너리를 실행할 때 바이너리 내부의 코드와 데이터를 세그먼트(segment)라는 논리적인 영역으로 구분한다.

세그먼트는 링크 시 사용되는 섹션과는 달리 실행 시점에 사용된다.

  • /usr/include/elf.h의 Elf64_Shdr 구조체 정의
typedef struct {
  Elf64_Word	sh_name;        /* Section name (string tbl index) */
  Elf64_Word	sh_type;        /* Section type */
  Elf64_Xword	sh_flags;       /* Section flags */
  Elf64_Addr	sh_addr;        /* Section virtual addr at execution */
  Elf64_Off	sh_offset;        /* Section file offset */
  Elf64_Xword	sh_size;        /* Section size in bytes */
  Elf64_Word	sh_link;        /* Link to another section */
  Elf64_Word	sh_info;        /* Additional section information */
  Elf64_Xword	sh_addralign;   /* Section alignment */
  Elf64_Xword	sh_entsize;     /* Entry size if section holds table */
} Elf64_Shdr;
  • 섹션 헤더의 각 필드
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  
    •  

Sections

GNU/Linux 시스템의 ELF 파일들은 대부분 표준적인 섹션 구성으로 이루어져 있다.

$ readelf --sections --wide a.out

There are 29 section headers, starting at offset 0x1168:

Section Headers:
  [Nr] Name           Type      Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                NULL      0000000000000000 000000 000000 00      0   0  0
  [ 1] .interp        PROGBITS  0000000000400238 000238 00001c 00   A  0   0  1
  [ 2] .note.ABI-tag  NOTE      0000000000400254 000254 000020 00   A  0   0  4
  [ 3] .note.gnu.build-id NOTE     0000000000400274 000274 000024 00   A  0   0  4
  [ 4] .gnu.hash      GNU_HASH  0000000000400298 000298 00001c 00   A  5   0  8
  [ 5] .dynsym        DYNSYM    00000000004002b8 0002b8 000060 18   A  6   1  8
  [ 6] .dynstr        STRTAB    0000000000400318 000318 00003d 00   A  0   0  1
  [ 7] .gnu.version   VERSYM    0000000000400356 000356 000008 02   A  5   0  2
  [ 8] .gnu.version_r VERNEED   0000000000400360 000360 000020 00   A  6   1  8
  [ 9] .rela.dyn      RELA      0000000000400380 000380 000018 18   A  5   0  8
  [10] .rela.plt      RELA      0000000000400398 000398 000030 18  AI  5  24  8
  [11] .init          PROGBITS  00000000004003c8 0003c8 00001a 00  AX  0   0  4
  [12] .plt           PROGBITS  00000000004003f0 0003f0 000030 10  AX  0   0 16
  [13] .plt.got       PROGBITS  0000000000400420 000420 000008 00  AX  0   0  8
  [14] .text          PROGBITS  0000000000400430 000430 000192 00  AX  0   0 16
  [15] .fini          PROGBITS  00000000004005c4 0005c4 000009 00  AX  0   0  4
  [16] .rodata        PROGBITS  00000000004005d0 0005d0 000012 00   A  0   0  4
  [17] .eh_frame_hdr  PROGBITS  00000000004005e4 0005e4 000034 00   A  0   0  4
  [18] .eh_frame      PROGBITS  0000000000400618 000618 0000f4 00   A  0   0  8
  [19] .init_array    INIT_ARRAY0000000000600e10 000e10 000008 00  WA  0   0  8
  [20] .fini_array    FINI_ARRAY0000000000600e18 000e18 000008 00  WA  0   0  8
  [21] .jcr           PROGBITS  0000000000600e20 000e20 000008 00  WA  0   0  8
  [22] .dynamic       DYNAMIC   0000000000600e28 000e28 0001d0 10  WA  6   0  8
  [23] .got           PROGBITS  0000000000600ff8 000ff8 000008 08  WA  0   0  8
  [24] .got.plt       PROGBITS  0000000000601000 001000 000028 08  WA  0   0  8
  [25] .data          PROGBITS  0000000000601028 001028 000010 00  WA  0   0  8
  [26] .bss           NOBITS    0000000000601038 001038 000008 00  WA  0   0  1
  [27] .comment       PROGBITS  0000000000000000 001038 000034 01  MS  0   0  1
  [28] .shstrtab      STRTAB    0000000000000000 00106c 0000fc 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)
  • .init 섹션에는 초기화에 필요한 실행 코드가 포함된다. 운영체제의 제어권이 바이너리의 메인 엔트리로 넘어가면 이 섹션의 코드부터 실행된다.
  • .fini 섹션은 메인 프로그램이 완료된 후에 실행된다. .init과 반대로 소멸자 역할을 한다.
  • .init_array 섹션은 일종의 생성자로 사용할 함수에 대한 포인터 배열이 포함된다. 각 함수는 메인 함수가 호출되기 전에 초기화되며 차례로 호출된다. .init_array는 데이터 섹션으로 사용자 정의 생성자에 대한 포인터를 포함해 원하는 만큼 함수 포인터를 포함할 수 있다.
  • .fini_array 섹션은 소멸자에 대한 포인터 배열이 포함된다. .init_array와 유사하다. 이전 버전의 gcc로 생성한 바이너리는 .ctors와 .dtors라고 부른다.
  • .text 섹션에는 메인 함수 코드가 존재한다. 사용자 정의 코드를 포함하기 때문에 SHT_PROGBITS라는 타입으로 설정되어 있다. 또한 실행 가능하지만 쓰기는 불가능해 섹션 플래그는 AX다. _start, register_tm_clones, frame_dummy와 같은 여러 표준 함수가 포함된다.
  • .rodata 섹션에는 상숫값과 같은 읽기 전용 데이터가 저장된다.
  • .data 섹션은 초기화된 변수의 기본값이 저장된다. 이 값은 변경되어야 하므로 쓰기 가능한 영역이다.
  • .bss 섹션은 초기화되지 않은 변수들을 위해 예약된 공간이다. BSS는 심벌에 의해 시작되는 블록 영역(Block Strarted by Symbol)이라는 의미로, (심벌) 변수들이 저장될 메모리 블록으로 사용한다.
  • .rel.*와 .rela.* 형식의 섹션들은 재배치 과정에서 링커가 활용할 정보를 담고 있다. 모두 SHT_RELA 타입이며 재배치 항목들을 기재한 테이블이다. 테이블의 각 항목은 재배치가 적용돼야 하는 주소와 해당 주소에 연결해야 하는 정보를 저장한다.동적 링킹 단계에서 수행할 동적 재배치만 남아 있다. 다음은 동적 링킹의 가장 일반적인 두 타입이다.
  • GLOB_DAT(global data): 이 재배치는 재배치는 데이터 심벌의 주소를 계산하고 .got의 오프셋에 연결하는 데 사용된다. 오프셋이 .got 섹션의 시작 주소를 나타낸다.이 엔트리의 오프셋은 해당 함수에서 간접 점프하는 점프 슬롯의 주소(rip로부터의 상대 주소로 계산)다.
  • JUMP_SLO(jump slots): .got.plt 섹션에 오프셋이 있으며 라이브러리 함수의 주소가 연결될 수있는 슬롯을 나타냅니다. 엔트리는 점프 슬롯(jump slot)이라고 부른다.
  • .dynamic 섹션은 바이너리가 로드될 때 운영체제와 동적 링커에게 일종의 road map을 제시하는 역할을 한다. 일명 태그(tag)라고 하는 Elf64_dyn 구조의 테이블을 포함한다. 태그는 번호로 구분한다.DT_NEEDED 태그는 바이너리와 의존성 관계를 가진 정보를 동적 링커에게 알려준다.게다가 동적 링커의 수행에 필요한 중요한 정보들을 가리키는 역할을 하기도 한다. 예를 들어 동적 문자열 테이블(DT_STRTAB), 동적 심벌 테이블(DT_SYMTAB), .got.plt 섹션(DT_PLTGOT), 동적 재배치 섹션(DT_RELA) 등.
  • DT_VERNEED와 DT_VERNEEDNUM 태그는 버전 의존성 테이블(version dependency table)의 시작 주소와 엔트리 수를 지정한다.
  • .shstrtab 섹션은 섹션의 이름을 포함하는 문자열 배열이다. 각 이름들을 숫자로 인덱스가 매겨져 있다.
  • .symtab 섹션에는 Elf64_Sym 구조체의 테이블인 심벌 테이블이 포함되어 있다. 각 심벌 테이블은 심벌명을 함수나 변수와 같이 코드나 데이터와 연관시킨다.
  • .strtab 섹션에는 심벌 이름을 포함한 실제 문자열들이 위치한다. 이 문자열들 Elf64_Sym 테이블과 연결된다. 스트립 된 바이너리에는 .symtab과 .strtab 테이블은 전부 삭제된다.
  • .dynsym 섹션과 .dynstr 섹션은 동적 링킹에 필요한 심벌과 문자열 정보를 담고 있다는 점을 제외하면 .symtab이나 .strtab와 유사하다.정적 심벌 테이블은 섹션 타입이 SHT_SYMTAB이고 동적 심벌 테이블은 SHT_DYNSYM 타입이다.

Program Headers

프로그램 헤더 테이블은 바이너리를 세그먼트의 관점에서 볼 수 있게 해준다.

바이너리를 섹션 관점에서 보는 것은 정적 링킹의 목적만으로 한정하는 것이다.

세그먼트의 관점으로 본다는 것은 운영체제와 동적 링킹 과정을 통해 바이너리가 프로세스의 형태가 되고, 그와 관련된 코드와 데이터들을 어떻게 처리할 것인지를 다룬다는 의미다.

  • /usr/include/elf.h의 Elf64_Phdr 정의
typedef struct elf64_phdr {
  Elf64_Word p_type;      /* Segment type */
  Elf64_Word p_flags;     /* Segment flags */
  Elf64_Off p_offset;     /* Segment file offset */
  Elf64_Addr p_vaddr;     /* Segment virtual address */
  Elf64_Addr p_paddr;     /* Segment physical address */
  Elf64_Xword p_filesz;   /* Segment size in file */
  Elf64_Xword p_memsz;    /* Segment size in memory */
  Elf64_Xword p_align;    /* Segment alignment, file & memory */
} Elf64_Phdr;
  • readelf로 프로그램 헤더 테이블 확인
$ readelf --wide --segments a.out

Elf file type is EXEC (Executable file)
Entry point 0x400430
There are 9 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R E 0x8
  INTERP         0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R   0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x000000 0x0000000000400000 0x0000000000400000 0x00070c 0x00070c R E 0x200000
  LOAD           0x000e10 0x0000000000600e10 0x0000000000600e10 0x000228 0x000230 RW  0x200000
  DYNAMIC        0x000e28 0x0000000000600e28 0x0000000000600e28 0x0001d0 0x0001d0 RW  0x8
  NOTE           0x000254 0x0000000000400254 0x0000000000400254 0x000044 0x000044 R   0x4
  GNU_EH_FRAME   0x0005e4 0x00000000004005e4 0x00000000004005e4 0x000034 0x000034 R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x000e10 0x0000000000600e10 0x0000000000600e10 0x0001f0 0x0001f0 R   0x1

➊ Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
   03     .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
   04     .dynamic
   05     .note.ABI-tag .note.gnu.build-id
   06     .eh_frame_hdr
   07
   08     .init_array .fini_array .jcr .dynamic .got

➊에서 섹션과 세그먼트의 매핑을 확인할 수 있다. 이를 통해 세그먼트는 여러 개(0개 이상)의 섹션들을 묶은 형태라는 것을 알 수 있다.


Lazy Binding

바이너리가 프로세스의 형태로 메모리에 로드될 때 동적 링커에 의해 최종적인 재배치가 이루어진다.

예를 들어, 공유 라이브러리의 함수를 호출할 때 컴파일 시에는 해당 주솟값을 미확정인 상태로 두고, 실행 시점에 참조해 로드 한다. 특히 대부분의 재배치 작업은 첫 번째 참조가 이루어지는 시점에 수행되는 일명 지연 바인딩(lazy binding) 기법을 사용한다.

지연 바인딩은 바이너리가 실행되는 시점에서 실제로 호출하는 함수만 재배치하도록 해준다.

리눅스 ELF 바이너리의 지연 바인딩은 PLT(Procedure Linkage Table)와 GOT(Global Offset Table) 섹션을 통해 구현된다.

ELF 바이너리는 .got.plt라는 또 하나의 GOT 섹션을 이용하며, 이는 .plt 섹션과의 연동을 위한 목적이다. 결국 .got.plt 섹션은 보통 .got 섹션과 유사하며 편의상 둘이 같다고 가정하자.

아래 그림은 PLT와 GOT를 이용한 지연 바인딩 과정을 그림으로 나타낸 것이다.

  • Calling a shared library function via the PLT

.plt 영역은 실행 가능한 코드가 담겨 있는 코드 섹션이며, .got.plt는 데이터 섹션이다.

.plt 섹션을 디스어셈블해 살펴보자.

$ objdump -M intel --section .plt -d a.out

a.out:     file format elf64-x86-64

Disassembly of section .plt:

➊ 00000000004003f0 <puts@plt-0x10>:
  4003f0:	ff 35 12 0c 20 00    	push   QWORD PTR [rip+0x200c12]        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
  4003f6:	ff 25 14 0c 20 00    	jmp    QWORD PTR [rip+0x200c14]        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
  4003fc:	0f 1f 40 00          	nop    DWORD PTR [rax+0x0]

➋ 0000000000400400 <puts@plt>:
  400400:	ff 25 12 0c 20 00    	jmp    QWORD PTR [rip+0x200c12]        # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
  400406:	68 00 00 00 00       	push   0x0 ➌
  40040b:	e9 e0 ff ff ff       	jmp    4003f0 <_init+0x28>

➍ 0000000000400410 <__libc_start_main@plt>:
  400410:	ff 25 0a 0c 20 00    	jmp    QWORD PTR [rip+0x200c0a]        # 601020 <_GLOBAL_OFFSET_TABLE_+0x20>
  400416:	68 01 00 00 00       	push   0x1 ➎
  40041b:	e9 d0 ff ff ff       	jmp    4003f0 <_init+0x28>

PLT는 <puts@plt-0x10>:와 같이 구성되어 있다. 다음으로 일련의 함수들이 나타나며 모두 라이브러리 함수 각각에 대한 것이고 스택에 값이 1씩 증가되며 push 한다.

  • PLT를 사용해 동적으로 라이브러리 함수 참조

라이브러리 함수 중 하나인 puts 함수 호출할 때 PLT 구조를 사용해 puts@plt와 같이 호출할 수 있다➊.

PLT 구문은 간접 점프 명령으로 시작하며, .got.plt 섹션에 저장된 주소로 점프한다➋. 지연 바인딩 전에는 이 주소가 puts@plt의 다음 명령어 주소를 가리키고 있다.

스택에 push 하는 값은 PLT 구문에서 함수들을 식별하기 위한 번호다➌.

다음 명령을 통해 default stub으로 이동한다➍.

default stub은 GOT에서 가져온 또 다른 식별자를 스택에 push하고, 동적 링커 부분으로 점프(GOT로 다시 간접 점프)한다➎.

PLT 구문에 의해 스택에 push된 이 식별 정보를 통해 동적 링커는 puts 함수 주소를 찾을 수 있음을 확인하고, puts 함수를 대신 호출한다. 동적 링커는 puts 함수 주소를 찾고 puts@plt와 관련된 GOT 테이블의 항목에 해당 함수의 주소를 연결(기록)한다.

이후 puts@plt를 호출하면 GOT 테이블 내부에는 패치를 통해 실제 puts 함수의 주소가 저장되어 있으므로 PLT 구문으로 점프될 때 (앞서 다룬) 동적 링커 작업을 반복하지 않고 즉시 puts 함수로 점프한다➏.

  • GOT를 사용하는 이유

PLT 코드에 라이브러리 주소를 바로 쓰지 않고 GOT와 함께 사용하는 이유는 보안상의 문제 때문이다. 바이너리에 취약점이 존재하는 경우 공격자가 PLT overwrite를 이용해 exploit 할 수 있기 때문이다. 물론 GOT 내부의 주소를 변경해 공격하는 GOT overwrite 기법도 발표되긴 하였으나 난이도가 더 높다.

또 다른 이유는 공유 라이브러리의 코드 공유성과 관련이 있다.

  • PLT GOT 동작 과정 분석

https://rond-o.tistory.com/216?category=844537

블로그 이미지

wtdsoul

,

https://bakjuna.tistory.com/135?category=816799 

 

[solana] 솔라나 스마트 컨트랙트 만들어보기

수정: 실제로 현업에서 작동하는 프로그램을 제작하시려면 https://bakjuna.tistory.com/143 여길 참조해주세요! 이 글에선 솔라나 네이티브 코드로 제작하는 법을 설명하고 있습니다. 1. 들어가며 솔라

bakjuna.tistory.com

 

수정: 실제로 현업에서 작동하는 프로그램을 제작하시려면 https://bakjuna.tistory.com/143 여길 참조해주세요! 이 글에선 솔라나 네이티브 코드로 제작하는 법을 설명하고 있습니다.

1. 들어가며

솔라나는 최근 아주 각광받는 레이어1 코인입니다. 일단 gas fee가 이더리움에 비해 압도적으로 저렴하고, PoH라는 새로운 접근 방식을 통해 초당 트랜잭션 수도 아주 뛰어나 무려 초당 5만 개에 달하는 트랜잭션을 처리할 수 있습니다. 기존 비트코인, 이더리움의 초당 10여 개에 불과한 트랜잭션 수와 비교하면 아주 장족의 발전이죠.

 

트랜잭션의 gas fee도 현재 5000Lamport (0.000000001SOL) 에 불과해 20만원이 1솔라나라고 가정하면 트랜잭션당 소모되는 gas fee가 10원에 불과합니다. 해외 송금 해보신 분들은 아실거에요. 이 수치가 얼마나 대단한 것인지... 순식간에 이체되고, 아주 적은 비용으로 송금이 가능합니다.

 

솔라나는 당연히 최신 기술인 NFT 민팅과 Smart Contract, Defi 등을 지원합니다. 이번 글에선, 이 모든 기술들의 근간이 될 스마트 컨트랙트를 빌딩하는 방법에 대해서 알아보려고 합니다.

 

2. 스마트 컨트랙트란?

사실 많은 분들이 스마트 컨트랙트가 뭔지 구체적으로 알지 못하고 계시지만, 개념은 엄청 간단합니다. 그냥 자판기를 생각하시면 됩니다. 내가 어떤 일을 하면 어떤 결과가 나올지 미리 정해진 스크립트에 따라 수행되는 것이죠! 인터넷에 수행될 코드를 미리 업로드시켜놓고, 수행 조건이 만족되면 해당 코드가 자동으로 실행되고 연산됩니다. 이게 답니다!

 

그럼 이게 왜 혁신적이냐고요? 왜냐면, 기존에는 다들 '신뢰'에 기초해서 하던 작업들을 이젠 딱히 상대를 신뢰하지 않아도 되거든요. 예를 들면 제가 어떤 게임을 하고 이겼을 때 1000원을 받는다고 해봅시다. 종전에는 이 게임을 하고 1000원을 받는 행위 자체를 해당 사이트를 '신뢰'하지 않으면 할 수 없었습니다. 게임 사이트가 나에게 돈을 줄지, 주지 않을지 어떻게 아나요?

 

하지만 블록체인 스마트 컨트랙트는 다릅니다. 스마트 컨트랙트 온체인에서 일어나는 모든 일들은 스크립트를 읽을 수 있는 능력만 있다면 게임사이트가 특정 조건을 만족하면 자동으로 나에게 돈을 준다는 사실을 알 수 있습니다. 그렇지 않다면, 교묘하게 그렇지 않은 코드를 삽입했다는 사실도 알아낼 수 있죠. 현재는 일부 프로그래머만이 해당 사실을 검증할 수 있겠습니다만, 적어도 모두에게 공개되어있는 코드에 대놓고 스캠 코드를 삽입할 수는 없겠죠?

 

스마트 컨트랙트에 대한 대략적인 설명입니다. 먼저 프로그램된 컨트랙트 (계약)을 올려놓고, 이벤트가 진행이 되면 해당 이벤트가 실행이 됩니다. 그 실행 내역에 따라서 토큰 (뭐... 돈이죠) 이 오가는 것을 보증할 수 있습니다.

 

3. 스마트 컨트랙트 예제 살펴보기

3.1) 설치

 

솔라나 스마트 컨트랙트 예제를 살펴봅시다. 솔라나는 스마트 컨트랙트는 러스트로 짜여져 있고, 소통은 node로 할 수 있습니다.

 

 

  git clone git@github.com:solana-labs/example-helloworld.git
  sh -c "$(curl -sSfL https://release.solana.com/v1.9.1/install)"

 

이 프로젝트를 받아봅시다. 솔라나의 예제 프로젝트에요. 그리고, 솔라나도 한번 깔아봅시다. 두 번째 줄이 솔라나 CLI를 설치하는 구문입니다.

 

설치하고 나서 한번 살펴볼까요?

 

 

  solana config set --url https://api.devnet.solana.com

 

솔라나 데브넷으로 설정해보면, 다음과 같은 설정 완료창이 뜨는 것을 알 수 있습니다.

 

 

solana config 파일 저장 위치와, keypair 위치가 뜹니다. 제 솔라나 월렛 키페어가 만들어져있기 때문에 뜨는 것이죠. 만약 keypair가 뜨지 않는다면, 생성해주셔야 합니다.

 

 

 

  solana-keygen new

 

솔라나 키를 이 명령어로 생성해줄 수 있습니다.

 

3.2) 스마트 컨트랙트

솔라나는 러스트를 스마트 컨트랙트 언어로 사용한다고 했습니다. 러스트 기본 언어 문법은 배워두는게 좋습니다. 모른다고 하더라도 잠시 작성할 수는 있겠지만, 어쨌든 기초적인 것들은 알아두는게 좋으니까요.

 

solana-helloworld 프로젝트를 살펴보시면 program-rust/src/lib.rs 파일이 존재합니다. 이게 러스트 파일인데요, 이 파일이 컴파일되면 솔라나 스마트 컨트랙트가 됩니다. 한번 해당 파일을 살펴봅시다.

 

 

 

  use borsh::{BorshDeserialize, BorshSerialize};
  use solana_program::{
  account_info::{next_account_info, AccountInfo},
  entrypoint,
  entrypoint::ProgramResult,
  msg,
  program_error::ProgramError,
  pubkey::Pubkey,
  };
   
  /// Define the type of state stored in accounts
  #[derive(BorshSerialize, BorshDeserialize, Debug)]
  pub struct GreetingAccount {
  /// number of greetings
  pub counter: u32,
  }
   
  // Declare and export the program's entrypoint
  entrypoint!(process_instruction);
   
  // Program entrypoint's implementation
  pub fn process_instruction(
  program_id: &Pubkey, // Public key of the account the hello world program was loaded into
  accounts: &[AccountInfo], // The account to say hello to
  instruction_data: &[u8], // Ignored, all helloworld instructions are hellos
  ) -> ProgramResult {
  msg!("Hello World Rust program entrypoint");
   
  // Iterating accounts is safer then indexing
  let accounts_iter = &mut accounts.iter();
   
  // Get the account to say hello to
  let account = next_account_info(accounts_iter)?;
   
  // The account must be owned by the program in order to modify its data
  if account.owner != program_id {
  msg!("Greeted account does not have the correct program id");
  return Err(ProgramError::IncorrectProgramId);
  }
   
  // Increment and store the number of times the account has been greeted
  let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
  let num: u32 = instruction_data[0] as u32;
  greeting_account.counter += num;
  greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;
   
  msg!("Greeted {} time(s)!", greeting_account.counter);
   
  Ok(())
  }
   
  // Sanity tests
  #[cfg(test)]
  mod test {
  use super::*;
  use solana_program::clock::Epoch;
  use std::mem;
   
  #[test]
  fn test_sanity() {
  let program_id = Pubkey::default();
  let key = Pubkey::default();
  let mut lamports = 0;
  let mut data = vec![0; mem::size_of::<u32>()];
  let owner = Pubkey::default();
  let account = AccountInfo::new(
  &key,
  false,
  true,
  &mut lamports,
  &mut data,
  &owner,
  false,
  Epoch::default(),
  );
  let instruction_data: Vec<u8> = Vec::new();
   
  let accounts = vec![account];
   
  assert_eq!(
  GreetingAccount::try_from_slice(&accounts[0].data.borrow())
  .unwrap()
  .counter,
  0
  );
  process_instruction(&program_id, &accounts, &instruction_data).unwrap();
  assert_eq!(
  GreetingAccount::try_from_slice(&accounts[0].data.borrow())
  .unwrap()
  .counter,
  1
  );
  process_instruction(&program_id, &accounts, &instruction_data).unwrap();
  assert_eq!(
  GreetingAccount::try_from_slice(&accounts[0].data.borrow())
  .unwrap()
  .counter,
  2
  );
  }
  }
view rawlib.rs hosted with ❤ by GitHub

 

조금 긴데 사실 간단합니다. 지금 단계에서 알아야 할 내용은 얼마 없거든요.

 

borsh는 Binary Object Representation Serializer for Hashing 의 약어입니다. 바이너리로 풀어진 오브젝트를 시리얼라이징하거나 디시리얼라이징할 때 쓰이는 일종의 라이브러리라고 생각하시면 됩니다. node에도 동일하게 존재하는 라이브러리입니다.

 

entrypoint!() 에서 실제 스마트 컨트랙트가 선언되는데, 이 안 내용을 한번 살펴보시죠.

 

account.iter()는 map과 비슷한겁니다. account를 iterable하게 돌려서 account를 하나씩 살펴본다는 의미입니다. 그래서 next_account_info로 account를 가지고 온 후, 해당 account_info에 데이터를 set해줄 준비를 할 겁니다. 데이터를 저장해야 그 데이터로 무언가 로직을 돌릴테니, 이번 예제에선 데이터를 저장하는 로직만 해볼거에요. 그러니까... UPDATE, INSERT, SELECT 세 기능을 구현해 볼 겁니다.

 

 

  let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
  let num: u32 = instruction_data[0] as u32;
  greeting_account.counter += num;
  greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;
   
  msg!("Greeted {} time(s)!", greeting_account.counter);
   
  Ok(())

 

여기가 핵심 로직인데요, account의 data를 가지고 와서, instruction_data를 해당 data에 set 해주는 부분입니다. instruction_data는 우리가 직접 넣어주는 데이터가 될 거에요. 그 다음 다시 저장해주고 Ok() 해주면, 해당 노드 블럭에 스마트 컨트랙트 내용이 저장됩니다.

 

여기까지 간단하게 러스트 코드를 살펴봤습니다. 너무 간단해서 볼 내용도 별로 없죠?

 

3.3) 데이터 set 하고 불러오기

부차적인 내용은 다 빼고, 하나하나 차근차근 빠르게 보겠습니다.

 

1] 커넥션 맺기

 

  const rpcUrl = await getRpcUrl();
  connection = new Connection(rpcUrl, 'confirmed');
  const version = await connection.getVersion();
  console.log('Connection to cluster established:', rpcUrl, version);

 

rpcUrl은 devNet 주소입니다. jsonRPC로 통신할 url이 어딘지 fetch해오거나 아니면 선언해주는 곳입니다. 그 이후, confirmed 블록만 가져와서 커넥션을 맺어주는걸 new Connection을 통해 진행합니다.

 

 

 

  let fees = 0;
  if (!payer) {
  const {feeCalculator} = await connection.getRecentBlockhash();
   
  // Calculate the cost to fund the greeter account
  fees += await connection.getMinimumBalanceForRentExemption(GREETING_SIZE);
   
  // Calculate the cost of sending transactions
  fees += feeCalculator.lamportsPerSignature * 100; // wag
   
  payer = await getPayer();
  }
   
  let lamports = await connection.getBalance(payer.publicKey);
  if (lamports < fees) {
  // If current balance is not enough to pay for fees, request an airdrop
  const sig = await connection.requestAirdrop(
  payer.publicKey,
  fees - lamports,
  );
  await connection.confirmTransaction(sig);
  lamports = await connection.getBalance(payer.publicKey);
  }
   
  console.log(
  'Using account',
  payer.publicKey.toBase58(),
  'containing',
  lamports / LAMPORTS_PER_SOL,
  'SOL to pay for fees',
  );
view rawgetPayer.ts hosted with ❤ by GitHub

 

payer를 정해줍니다. 이번엔 devnet이기 때문에, payer는 우리죠. 따라서 만약 부족하면 데브넷에서 에어드롭을 받는 로직까지 추가합니다. 실제 디앱에선 이렇게 하면 안되고 에어드롭 받는 부분은 제외해야합니다. 만약 잔액이 부족하면 그냥 에러를 뱉어야죠.

 

 

 

  try {
  const programKeypair = await createKeypairFromFile(PROGRAM_KEYPAIR_PATH);
  programId = programKeypair.publicKey;
  } catch (err) {
  const errMsg = (err as Error).message;
  throw new Error(
  `Failed to read program keypair at '${PROGRAM_KEYPAIR_PATH}' due to error: ${errMsg}. Program may need to be deployed with \`solana program deploy dist/program/helloworld.so\``,
  );
  }

 

프로그램 에러가 있는지, 프로그램이 있긴 한지 체크해봅니다.

 

 

 

  const instruction = new TransactionInstruction({
  keys: [{pubkey: greetedPubkey, isSigner: false, isWritable: true}],
  programId,
  data: Buffer.alloc(1, 2), // 실제 넣을 데이터
  });
   
  await sendAndConfirmTransaction(
  connection,
  new Transaction().add(instruction),
  [payer],
  );
view rawtransaction.ts hosted with ❤ by GitHub

 

이제 실제로 트랜잭션을 발생시킵니다. TransactionInstruction의 input이 아까 러스트랑 동일하죠? 맞습니다, 러스트에서 받는 인자들입니다. 따라서 data에 저렇게 넣으면 2라는 숫자가 들어갑니다. 중요한건, Buffer로 선언된 ㄹㅇ 바이너리 숫자가 들어간다는 사실입니다.

 

 

 

  const accountInfo = await connection.getAccountInfo(greetedPubkey);
  if (accountInfo === null) {
  throw 'Error: cannot find the greeted account';
  }
  const greeting = borsh.deserialize(
  GreetingSchema,
  GreetingAccount,
  accountInfo.data,
  );

 

트랜잭션이 맺어지고 난 이후 현재 데이터는 어떻게 불러올까요? getAccountInfo를 통해 가져와서, data를 불러옵니다. 그러면 우리가 set한 데이터 정보들이 나옵니다!

 

 

4. 마무리

이렇게 솔라나로 아주 간단한 스마트 컨트랙트를 만들어 봤습니다. 노드를 통해 통신할 수 있으니, 아마 노드 웹서버를 통해 통신할 수도 있겠지요.

 

이런 스마트 컨트랙트를 openDB, open Logic으로도 사용할 수 있습니다. 누구나 볼 수 있는 DB, 그리고 누구나 볼 수 있는 로직이기 때문에 절대로 속일 수 없다는 특징을 가지게 된 것이죠. 누구나 검증할 수 있게 된 것입니다. 물론, 스마트컨트랙트를 누구나 발생시킬 수 있기 때문에, 실제 구현상에선 greetedPubKey의 SEED를 적절하게 잘 숨겨서 보관하는 것도 중요합니다. 해당 seed가 곧 DB의 암호가 되는 셈이니까요.

 

이 글이 한국어 사용자의 스마트 컨트랙트 이해도 향상에 조금이나마 도움이 되었으면 좋겠습니다! 기회가 된다면 다음 글로 곧 스마트컨트랙트의 실제 활용도 한번 보여드리겠습니다.

 

추가)

사실 프로그램을 만들 때엔 anchor를 이용하시는 것이 좋습니다. 해당 글도 읽어보세요!

https://bakjuna.tistory.com/138

 

[anchor] anchor를 이용하여 solana program (smart contract) 작성하기

1. 들어가며 anchor는 solana 프로그램을 작성할 때 훨씬 더 쉽게 작성할 수 있게 도움을 주는 라이브러리입니다. 솔라나 프로그램을 네이티브로 작성하는 것보다, anchor를 이용하여 작성하는게 훨씬

bakjuna.tistory.com

 

블로그 이미지

wtdsoul

,

https://www.skyer9.pe.kr/wordpress/?p=4518 

 

Ubuntu 20.04 ARM Cross Compile 하기 – 상구리의 기술 블로그

Ubuntu 20.04 ARM Cross Compile 하기 기초지식 ARM 은 hard float(하드웨어 GPU) 가 있는 버전이 있고, 없는 버전이 있습니다. EABI(Embedded Application Binary Interface)는, ARM의 C 호출 관행이라고 이해하면 됩니다. 툴

www.skyer9.pe.kr

 

Ubuntu 20.04 ARM Cross Compile 하기

기초지식

ARM 은 hard float(하드웨어 GPU) 가 있는 버전이 있고,
없는 버전이 있습니다.

EABI(Embedded Application Binary Interface)는,
ARM의 C 호출 관행이라고 이해하면 됩니다.

툴체인 설치

개발용 필수 라이브러리 설치

 sudo apt-get install build-essentialCOPY

hard float(하드웨어 GPU) 가 있는 경우

# gnu c compiler(32bit)
sudo apt-get install gcc-arm-linux-gnueabihf
# gnu c++ compiler(32bit)
sudo apt-get install g++-arm-linux-gnueabihfCOPY

hard float(하드웨어 GPU) 가 없는 경우

# gnu c compiler(32bit)
sudo apt-get install gcc-arm-linux-gnueabi
# gnu c++ compiler(32bit)
sudo apt-get install g++-arm-linux-gnueabiCOPY

64bit 버전

# gnu c compiler
sudo apt-get install gcc-aarch64-linux-gnu
# gnu c++ compiler
sudo apt-get install g++-aarch64-linux-gnuCOPY

컴파일

Hello, World!

vi hello.cpp
--------------------------
#include <iostream>
using namespace std;

int main() {
    cout << "Hello, World!" << endl;
    return 0;
}
--------------------------

arm-linux-gnueabihf-g++ -g -o hello hello.cpp
file hello
hello: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV) ......

aarch64-linux-gnu-g++ -g -o hello hello.cpp
file hello
hello: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV) ......COPY

make

우선 알아야 할 것은 make 가 직접적으로 cross compile 을 지원하는 것이 아니라,
Makefile 에 cross compile 을 지원하도록 설정해야 하는 것입니다.

들여쓰기는 TAB 문자로만 이루어져야 합니다.
공백문자가 있는 경우 오류가 발생합니다.

AR=${CROSS_COMPILE}ar
AS=${CROSS_COMPILE}as
LD=${CROSS_COMPILE}ld
CC=$(CROSS_COMPILE)gcc
CXX=$(CROSS_COMPILE)g++
NM=${CROSS_COMPILE}nm
RANLIB=${CROSS_COMPILE}ranlib

CFLAGS=""
CPPFLAGS=""
LDFLAGS=""
LIBS=""

hello : hello.cpp
        $(CXX) -g -o hello hello.cpp

clean:
        rm helloCOPY

make 를 이용하여 컴파일하는 경우, 아래와 같이 환경설정을 추가하고 컴파일하면 됩니다.

# 32bit, GPU 없는 경우
export CROSS_COMPILE=arm-linux-gnueabi-
export ARCH=arm
# 32bit, GPU 있는 경우
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
# 64bit
export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64

make

file hello
hello: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV) ......COPY

아래 명령을 .bashrc 에 추가해 놓으면 편합니다.

alias armmake='make -j8 ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- '
alias arm64make='make -j8 ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- 'COPY

cmake

샘플로 json-c 라이브러리를 컴파일합니다.

git clone https://github.com/json-c/json-c.git
cd json-c
mkdir build
cd build
# cmake ..COPY
vi ../toolchain.arm.cmake
-------------------------------
SET(CMAKE_C_COMPILER ${CROSS_COMPILE}gcc)
SET(CMAKE_CXX_COMPILER ${CROSS_COMPILE}g++)
SET(CMAKE_LINKER ${CROSS_COMPILE}ld)
SET(CMAKE_NM ${CROSS_COMPILE}nm)
SET(CMAKE_OBJCOPY ${CROSS_COMPILE}objcopy)
SET(CMAKE_OBJDUMP ${CROSS_COMPILE}objdump)
SET(CMAKE_RANLIB ${CROSS_COMPILE}ranlib)
-------------------------------COPY
cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.arm.cmake -DCROSS_COMPILE=aarch64-linux-gnu- ..

make
file libjson-c.so.5.1.0
libjson-c.so.5.1.0: ELF 64-bit LSB shared object, ARM aarch64, version ......COPY

configure

./configure --host=arm-linux-gnueabiCOPY
 
블로그 이미지

wtdsoul

,

https://domdom.tistory.com/596

 

[frida] 프리다 안드로이드 SSL/TLS 피닝 우회 스크립트

지난 글에서는 리패키징을 통한 SSL/TLS 피닝 우회 방법에 대해서 언급했었는데요. 아래 링크에서 참고해보실 수 있습니다. https://domdom.tistory.com/377 [apk-mitm] APK 파일 SSL/TLS pinning 우회 및 기능 없애

domdom.tistory.com

 

 

setImmediate(function(){
Java.perform(function() {
    var array_list = Java.use("java.util.ArrayList");
    var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
    TrustManagerImpl.checkTrustedRecursive.implementation = function(a1, a2, a3, a4, a5, a6) {
        var a = array_list.$new();
        return a;
    }
}, 0);
})

 

다만 요즘 금융권 앱의 경우에는 okhttpv3 이며 여러 클래스에서 pinning 을 하고 있어 다양하게 우회를 해야할 필요가 있습니다. 때문에 이럴 때 사용하기 좋은 코드를 찾았는데 아래와 같습니다. (길이가 좀 깁니다)

/* frida -U -f [APP_ID] -l frida_multiple_unpinning.js --no-pause */

setTimeout(function() {
	Java.perform(function() {
		console.log('');
		console.log('======');
		console.log('[#] Android Bypass for various Certificate Pinning methods [#]');
		console.log('======');


		var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
		var SSLContext = Java.use('javax.net.ssl.SSLContext');
		
		// TrustManager (Android < 7) //
		////////////////////////////////
		var TrustManager = Java.registerClass({
			// Implement a custom TrustManager
			name: 'dev.asd.test.TrustManager',
			implements: [X509TrustManager],
			methods: {
				checkClientTrusted: function(chain, authType) {},
				checkServerTrusted: function(chain, authType) {},
				getAcceptedIssuers: function() {return []; }
			}
		});
		// Prepare the TrustManager array to pass to SSLContext.init()
		var TrustManagers = [TrustManager.$new()];
		// Get a handle on the init() on the SSLContext class
		var SSLContext_init = SSLContext.init.overload(
			'[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom');
		try {
			// Override the init method, specifying the custom TrustManager
			SSLContext_init.implementation = function(keyManager, trustManager, secureRandom) {
				console.log('[+] Bypassing Trustmanager (Android < 7) pinner');
				SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
			};
		} catch (err) {
			console.log('[-] TrustManager (Android < 7) pinner not found');
			//console.log(err);
		}



	
		// OkHTTPv3 (quadruple bypass) //
		/////////////////////////////////
		try {
			// Bypass OkHTTPv3 {1}
			var okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner');    
			okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {                              
				console.log('[+] Bypassing OkHTTPv3 {1}: ' + a);
				return;
			};
		} catch (err) {
			console.log('[-] OkHTTPv3 {1} pinner not found');
			//console.log(err);
		}
		try {
			// Bypass OkHTTPv3 {2}
			// This method of CertificatePinner.check is deprecated but could be found in some old Android apps
			var okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner');    
			okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function(a, b) {
				console.log('[+] Bypassing OkHTTPv3 {2}: ' + a);
				return;
			};
		} catch (err) {
			console.log('[-] OkHTTPv3 {2} pinner not found');
			//console.log(err);
		}
		try {
			// Bypass OkHTTPv3 {3}
			var okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner');    
			okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function(a, b) {
				console.log('[+] Bypassing OkHTTPv3 {3}: ' + a);
				return;
			};
		} catch(err) {
			console.log('[-] OkHTTPv3 {3} pinner not found');
			//console.log(err);
		}
		try {
			// Bypass OkHTTPv3 {4}
			var okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner');    
			//okhttp3_Activity_4['check$okhttp'].implementation = function(a, b) {
			okhttp3_Activity_4.check$okhttp.overload('java.lang.String', 'kotlin.jvm.functions.Function0').implementation = function(a, b) {		
				console.log('[+] Bypassing OkHTTPv3 {4}: ' + a);
				return;
			};
		} catch(err) {
			console.log('[-] OkHTTPv3 {4} pinner not found');
			//console.log(err);
		}

	

	
		// Trustkit (triple bypass) //
		//////////////////////////////
		try {
			// Bypass Trustkit {1}
			var trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
			trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
				console.log('[+] Bypassing Trustkit {1}: ' + a);
				return true;
			};
		} catch (err) {
			console.log('[-] Trustkit {1} pinner not found');
			//console.log(err);
		}
		try {
			// Bypass Trustkit {2}
			var trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
			trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
				console.log('[+] Bypassing Trustkit {2}: ' + a);
				return true;
			};
		} catch (err) {
			console.log('[-] Trustkit {2} pinner not found');
			//console.log(err);
		}
		try {
			// Bypass Trustkit {3}
			var trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager');
			trustkit_PinningTrustManager.checkServerTrusted.overload('[Ljava.security.cert.X509Certificate;', 'java.lang.String').implementation = function(chain, authType) {
				console.log('[+] Bypassing Trustkit {3}');
				//return;
			};
		} catch (err) {
			console.log('[-] Trustkit {3} pinner not found');
			//console.log(err);
		}
		
	
	
  
		// TrustManagerImpl (Android > 7) //
		////////////////////////////////////
		try {
			// Bypass TrustManagerImpl (Android > 7) {1}
			var array_list = Java.use("java.util.ArrayList");
			var TrustManagerImpl_Activity_1 = Java.use('com.android.org.conscrypt.TrustManagerImpl');
			TrustManagerImpl_Activity_1.checkTrustedRecursive.implementation = function(certs, ocspData, tlsSctData, host, clientAuth, untrustedChain, trustAnchorChain, used) {
				console.log('[+] Bypassing TrustManagerImpl (Android > 7) checkTrustedRecursive check: '+ host);
				return array_list.$new();
			};
		} catch (err) {
			console.log('[-] TrustManagerImpl (Android > 7) checkTrustedRecursive check not found');
			//console.log(err);
		}  
		try {
			// Bypass TrustManagerImpl (Android > 7) {2} (probably no more necessary)
			var TrustManagerImpl_Activity_2 = Java.use('com.android.org.conscrypt.TrustManagerImpl');
			TrustManagerImpl_Activity_2.verifyChain.implementation = function(untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
				console.log('[+] Bypassing TrustManagerImpl (Android > 7) verifyChain check: ' + host);
				return untrustedChain;
			};   
		} catch (err) {
			console.log('[-] TrustManagerImpl (Android > 7) verifyChain check not found');
			//console.log(err);
		}

  
  
		

		// Appcelerator Titanium PinningTrustManager //
		///////////////////////////////////////////////
		try {
			var appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
			appcelerator_PinningTrustManager.checkServerTrusted.implementation = function(chain, authType) {
				console.log('[+] Bypassing Appcelerator PinningTrustManager');
				return;
			};
		} catch (err) {
			console.log('[-] Appcelerator PinningTrustManager pinner not found');
			//console.log(err);
		}




		// Fabric PinningTrustManager //
		////////////////////////////////
		try {
			var fabric_PinningTrustManager = Java.use('io.fabric.sdk.android.services.network.PinningTrustManager');
			fabric_PinningTrustManager.checkServerTrusted.implementation = function(chain, authType) {
				console.log('[+] Bypassing Fabric PinningTrustManager');
				return;
			};
		} catch (err) {
			console.log('[-] Fabric PinningTrustManager pinner not found');
			//console.log(err);
		}




		// OpenSSLSocketImpl Conscrypt (double bypass) //
		/////////////////////////////////////////////////
		try {
			var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
			OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certRefs, JavaObject, authMethod) {
				console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt {1}');
			};
		} catch (err) {
			console.log('[-] OpenSSLSocketImpl Conscrypt {1} pinner not found');
			//console.log(err);        
		}
		try {
			var OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
			OpenSSLSocketImpl.verifyCertificateChain.implementation = function(certChain, authMethod) {
				console.log('[+] Bypassing OpenSSLSocketImpl Conscrypt {2}');
			};
		} catch (err) {
			console.log('[-] OpenSSLSocketImpl Conscrypt {2} pinner not found');
			//console.log(err);        
		}




		// OpenSSLEngineSocketImpl Conscrypt //
		///////////////////////////////////////
		try {
			var OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl');
			OpenSSLEngineSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function(a, b) {
				console.log('[+] Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b);
			};
		} catch (err) {
			console.log('[-] OpenSSLEngineSocketImpl Conscrypt pinner not found');
			//console.log(err);
		}




		// OpenSSLSocketImpl Apache Harmony //
		//////////////////////////////////////
		try {
			var OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl');
			OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function(asn1DerEncodedCertificateChain, authMethod) {
				console.log('[+] Bypassing OpenSSLSocketImpl Apache Harmony');
			};
		} catch (err) {
			console.log('[-] OpenSSLSocketImpl Apache Harmony pinner not found');
			//console.log(err);      
		}




		// PhoneGap sslCertificateChecker //
		////////////////////////////////////
		try {
			var phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker');
			phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function(a, b, c) {
				console.log('[+] Bypassing PhoneGap sslCertificateChecker: ' + a);
				return true;
			};
		} catch (err) {
			console.log('[-] PhoneGap sslCertificateChecker pinner not found');
			//console.log(err);
		}




		// IBM MobileFirst pinTrustedCertificatePublicKey (double bypass) //
		////////////////////////////////////////////////////////////////////
		try {
			// Bypass IBM MobileFirst {1}
			var WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient');
			WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function(cert) {
				console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {1}: ' + cert);
				return;
			};
			} catch (err) {
			console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {1} pinner not found');
			//console.log(err);
		}
		try {
			// Bypass IBM MobileFirst {2}
			var WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient');
			WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function(cert) {
				console.log('[+] Bypassing IBM MobileFirst pinTrustedCertificatePublicKey {2}: ' + cert);
				return;
			};
		} catch (err) {
			console.log('[-] IBM MobileFirst pinTrustedCertificatePublicKey {2} pinner not found');
			//console.log(err);
		}




		// IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass) //
		///////////////////////////////////////////////////////////////////////////////////////////////////////
		try {
			// Bypass IBM WorkLight {1}
			var worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
			worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function(a, b) {
				console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {1}: ' + a);                
				return;
			};
		} catch (err) {
			console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {1} pinner not found');
			//console.log(err);
		}
		try {
			// Bypass IBM WorkLight {2}
			var worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
			worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
				console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {2}: ' + a);
				return;
			};
		} catch (err) {
			console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {2} pinner not found');
			//console.log(err);
		}
		try {
			// Bypass IBM WorkLight {3}
			var worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
			worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function(a, b) {
				console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {3}: ' + a);
				return;
			};
		} catch (err) {
			console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {3} pinner not found');
			//console.log(err);
		}
		try {
			// Bypass IBM WorkLight {4}
			var worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
			worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
				console.log('[+] Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning {4}: ' + a);
				return true;
			};
		} catch (err) {
			console.log('[-] IBM WorkLight HostNameVerifierWithCertificatePinning {4} pinner not found');
			//console.log(err);
		}




		// Conscrypt CertPinManager //
		//////////////////////////////
		try {
			var conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
			conscrypt_CertPinManager_Activity.checkChainPinning.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
				console.log('[+] Bypassing Conscrypt CertPinManager: ' + a);
				//return;
				return true;
			};
		} catch (err) {
			console.log('[-] Conscrypt CertPinManager pinner not found');
			//console.log(err);
		}
		
		


		// Conscrypt CertPinManager (Legacy) //
		///////////////////////////////////////
		try {
			var legacy_conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
			legacy_conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
				console.log('[+] Bypassing Conscrypt CertPinManager (Legacy): ' + a);
				return true;
			};
		} catch (err) {
			console.log('[-] Conscrypt CertPinManager (Legacy) pinner not found');
			//console.log(err);
		}

			   


		// CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager //
		///////////////////////////////////////////////////////////////////////////////////
		try {
			var cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager');
			cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
				console.log('[+] Bypassing CWAC-Netsecurity CertPinManager: ' + a);
				return true;
			};
		} catch (err) {
			console.log('[-] CWAC-Netsecurity CertPinManager pinner not found');
			//console.log(err);
		}




		// Worklight Androidgap WLCertificatePinningPlugin //
		/////////////////////////////////////////////////////
		try {
			var androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin');
			androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function(a, b, c) {
				console.log('[+] Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a);
				return true;
			};
		} catch (err) {
			console.log('[-] Worklight Androidgap WLCertificatePinningPlugin pinner not found');
			//console.log(err);
		}




		// Netty FingerprintTrustManagerFactory //
		//////////////////////////////////////////
		try {
			var netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory');
			//NOTE: sometimes this below implementation could be useful 
			//var netty_FingerprintTrustManagerFactory = Java.use('org.jboss.netty.handler.ssl.util.FingerprintTrustManagerFactory');
			netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function(type, chain) {
				console.log('[+] Bypassing Netty FingerprintTrustManagerFactory');
			};
		} catch (err) {
			console.log('[-] Netty FingerprintTrustManagerFactory pinner not found');
			//console.log(err);
		}




		// Squareup CertificatePinner [OkHTTP<v3] (double bypass) //
		////////////////////////////////////////////////////////////
		try {
			// Bypass Squareup CertificatePinner  {1}
			var Squareup_CertificatePinner_Activity_1 = Java.use('com.squareup.okhttp.CertificatePinner');
			Squareup_CertificatePinner_Activity_1.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function(a, b) {
				console.log('[+] Bypassing Squareup CertificatePinner {1}: ' + a);
				return;
			};
		} catch (err) {
			console.log('[-] Squareup CertificatePinner {1} pinner not found');
			//console.log(err);
		}
		try {
			// Bypass Squareup CertificatePinner {2}
			var Squareup_CertificatePinner_Activity_2 = Java.use('com.squareup.okhttp.CertificatePinner');
			Squareup_CertificatePinner_Activity_2.check.overload('java.lang.String', 'java.util.List').implementation = function(a, b) {
				console.log('[+] Bypassing Squareup CertificatePinner {2}: ' + a);
				return;
			};
		} catch (err) {
			console.log('[-] Squareup CertificatePinner {2} pinner not found');
			//console.log(err);
		}




		// Squareup OkHostnameVerifier [OkHTTP v3] (double bypass) //
		/////////////////////////////////////////////////////////////
		try {
			// Bypass Squareup OkHostnameVerifier {1}
			var Squareup_OkHostnameVerifier_Activity_1 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
			Squareup_OkHostnameVerifier_Activity_1.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function(a, b) {
				console.log('[+] Bypassing Squareup OkHostnameVerifier {1}: ' + a);
				return true;
			};
		} catch (err) {
			console.log('[-] Squareup OkHostnameVerifier check not found');
			//console.log(err);
		}    
		try {
			// Bypass Squareup OkHostnameVerifier {2}
			var Squareup_OkHostnameVerifier_Activity_2 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
			Squareup_OkHostnameVerifier_Activity_2.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function(a, b) {
				console.log('[+] Bypassing Squareup OkHostnameVerifier {2}: ' + a);
				return true;
			};
		} catch (err) {
			console.log('[-] Squareup OkHostnameVerifier check not found');
			//console.log(err);
		}


		

		// Android WebViewClient (quadruple bypass) //
		//////////////////////////////////////////////
		try {
			// Bypass WebViewClient {1} (deprecated from Android 6)
			var AndroidWebViewClient_Activity_1 = Java.use('android.webkit.WebViewClient');
			AndroidWebViewClient_Activity_1.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function(obj1, obj2, obj3) {
				console.log('[+] Bypassing Android WebViewClient check {1}');
			};
		} catch (err) {
			console.log('[-] Android WebViewClient {1} check not found');
			//console.log(err)
		}
		try {
			// Bypass WebViewClient {2}
			var AndroidWebViewClient_Activity_2 = Java.use('android.webkit.WebViewClient');
			AndroidWebViewClient_Activity_2.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function(obj1, obj2, obj3) {
				console.log('[+] Bypassing Android WebViewClient check {2}');
			};
		} catch (err) {
			console.log('[-] Android WebViewClient {2} check not found');
			//console.log(err)
		}
		try {
			// Bypass WebViewClient {3}
			var AndroidWebViewClient_Activity_3 = Java.use('android.webkit.WebViewClient');
			AndroidWebViewClient_Activity_3.onReceivedError.overload('android.webkit.WebView', 'int', 'java.lang.String', 'java.lang.String').implementation = function(obj1, obj2, obj3, obj4) {
				console.log('[+] Bypassing Android WebViewClient check {3}');
			};
		} catch (err) {
			console.log('[-] Android WebViewClient {3} check not found');
			//console.log(err)
		}
		try {
			// Bypass WebViewClient {4}
			var AndroidWebViewClient_Activity_4 = Java.use('android.webkit.WebViewClient');
			AndroidWebViewClient_Activity_4.onReceivedError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function(obj1, obj2, obj3) {
				console.log('[+] Bypassing Android WebViewClient check {4}');
			};
		} catch (err) {
			console.log('[-] Android WebViewClient {4} check not found');
			//console.log(err)
		}
		



		// Apache Cordova WebViewClient //
		//////////////////////////////////
		try {
			var CordovaWebViewClient_Activity = Java.use('org.apache.cordova.CordovaWebViewClient');
			CordovaWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function(obj1, obj2, obj3) {
				console.log('[+] Bypassing Apache Cordova WebViewClient check');
				obj3.proceed();
			};
		} catch (err) {
			console.log('[-] Apache Cordova WebViewClient check not found');
			//console.log(err);
		}




		// Boye AbstractVerifier //
		///////////////////////////
		try {
			var boye_AbstractVerifier = Java.use('ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier');
			boye_AbstractVerifier.verify.implementation = function(host, ssl) {
				console.log('[+] Bypassing Boye AbstractVerifier check: ' + host);
			};
		} catch (err) {
			console.log('[-] Boye AbstractVerifier check not found');
			//console.log(err);
		}




		// Apache AbstractVerifier //
		/////////////////////////////
		try {
			var apache_AbstractVerifier = Java.use('org.apache.http.conn.ssl.AbstractVerifier');
			apache_AbstractVerifier.verify.implementation = function(a, b, c, d) {
				console.log('[+] Bypassing Apache AbstractVerifier check: ' + a);
				return;
			};
		} catch (err) {
			console.log('[-] Apache AbstractVerifier check not found');
			//console.log(err);
		}




		// Chromium Cronet //
		/////////////////////    
		try {
			var CronetEngineBuilderImpl_Activity = Java.use("org.chromium.net.impl.CronetEngineBuilderImpl");
			// Setting argument to TRUE (default is TRUE) to disable Public Key pinning for local trust anchors
			CronetEngine_Activity.enablePublicKeyPinningBypassForLocalTrustAnchors.overload('boolean').implementation = function(a) {
				console.log("[+] Disabling Public Key pinning for local trust anchors in Chromium Cronet");
				var cronet_obj_1 = CronetEngine_Activity.enablePublicKeyPinningBypassForLocalTrustAnchors.call(this, true);
				return cronet_obj_1;
			};
			// Bypassing Chromium Cronet pinner
			CronetEngine_Activity.addPublicKeyPins.overload('java.lang.String', 'java.util.Set', 'boolean', 'java.util.Date').implementation = function(hostName, pinsSha256, includeSubdomains, expirationDate) {
				console.log("[+] Bypassing Chromium Cronet pinner: " + hostName);
				var cronet_obj_2 = CronetEngine_Activity.addPublicKeyPins.call(this, hostName, pinsSha256, includeSubdomains, expirationDate);
				return cronet_obj_2;
			};
		} catch (err) {
			console.log('[-] Chromium Cronet pinner not found')
			//console.log(err);
		}



		// Flutter Pinning packages http_certificate_pinning and ssl_pinning_plugin (double bypass) //
		//////////////////////////////////////////////////////////////////////////////////////////////
		try {
			// Bypass HttpCertificatePinning.check {1}
			var HttpCertificatePinning_Activity = Java.use('diefferson.http_certificate_pinning.HttpCertificatePinning');
			HttpCertificatePinning_Activity.checkConnexion.overload("java.lang.String", "java.util.List", "java.util.Map", "int", "java.lang.String").implementation = function (a, b, c ,d, e) {
				console.log('[+] Bypassing Flutter HttpCertificatePinning : ' + a);
				return true;
			};
		} catch (err) {
			console.log('[-] Flutter HttpCertificatePinning pinner not found');
			//console.log(err);
		}
		try {
			// Bypass SslPinningPlugin.check {2}
			var SslPinningPlugin_Activity = Java.use('com.macif.plugin.sslpinningplugin.SslPinningPlugin');
			SslPinningPlugin_Activity.checkConnexion.overload("java.lang.String", "java.util.List", "java.util.Map", "int", "java.lang.String").implementation = function (a, b, c ,d, e) {
				console.log('[+] Bypassing Flutter SslPinningPlugin: ' + a);
				return true;
			};
		} catch (err) {
			console.log('[-] Flutter SslPinningPlugin pinner not found');
			//console.log(err);
		}



		
		// Dynamic SSLPeerUnverifiedException Patcher                                //
		// An useful technique to bypass SSLPeerUnverifiedException failures raising //
		// when the Android app uses some uncommon SSL Pinning methods or an heavily //
		// code obfuscation. Inspired by an idea of: https://github.com/httptoolkit  //
		///////////////////////////////////////////////////////////////////////////////
		function rudimentaryFix(typeName) {
			// This is a improvable rudimentary fix, if not works you can patch it manually
			if (typeName === undefined){
				return;
			} else if (typeName === 'boolean') {
				return true;
			} else {
				return null;
			}
		}
		try {
			var UnverifiedCertError = Java.use('javax.net.ssl.SSLPeerUnverifiedException');
			UnverifiedCertError.$init.implementation = function (str) {
				console.log('\x1b[36m[!] Unexpected SSLPeerUnverifiedException occurred, trying to patch it dynamically...\x1b[0m');
				try {
					var stackTrace = Java.use('java.lang.Thread').currentThread().getStackTrace();
					var exceptionStackIndex = stackTrace.findIndex(stack =>
						stack.getClassName() === "javax.net.ssl.SSLPeerUnverifiedException"
					);
					// Retrieve the method raising the SSLPeerUnverifiedException
					var callingFunctionStack = stackTrace[exceptionStackIndex + 1];
					var className = callingFunctionStack.getClassName();
					var methodName = callingFunctionStack.getMethodName();
					var callingClass = Java.use(className);
					var callingMethod = callingClass[methodName];
					console.log('\x1b[36m[!] Attempting to bypass uncommon SSL Pinning method on: '+className+'.'+methodName+'\x1b[0m');					
					// Skip it when already patched by Frida
					if (callingMethod.implementation) {
						return; 
					}
					// Trying to patch the uncommon SSL Pinning method via implementation
					var returnTypeName = callingMethod.returnType.type;
					callingMethod.implementation = function() {
						rudimentaryFix(returnTypeName);
					};
				} catch (e) {
					// Dynamic patching via implementation does not works, then trying via function overloading
					//console.log('[!] The uncommon SSL Pinning method has more than one overload); 
					if (String(e).includes(".overload")) {
						var splittedList = String(e).split(".overload");
						for (let i=2; i<splittedList.length; i++) {
							var extractedOverload = splittedList[i].trim().split("(")[1].slice(0,-1).replaceAll("'","");
							// Check if extractedOverload has multiple arguments
							if (extractedOverload.includes(",")) {
								// Go here if overloaded method has multiple arguments (NOTE: max 6 args are covered here)
								var argList = extractedOverload.split(", ");
								console.log('\x1b[36m[!] Attempting overload of '+className+'.'+methodName+' with arguments: '+extractedOverload+'\x1b[0m');
								if (argList.length == 2) {
									callingMethod.overload(argList[0], argList[1]).implementation = function(a,b) {
										rudimentaryFix(returnTypeName);
									}
								} else if (argNum == 3) {
									callingMethod.overload(argList[0], argList[1], argList[2]).implementation = function(a,b,c) {
										rudimentaryFix(returnTypeName);
									}
								}  else if (argNum == 4) {
									callingMethod.overload(argList[0], argList[1], argList[2], argList[3]).implementation = function(a,b,c,d) {
										rudimentaryFix(returnTypeName);
									}
								}  else if (argNum == 5) {
									callingMethod.overload(argList[0], argList[1], argList[2], argList[3], argList[4]).implementation = function(a,b,c,d,e) {
										rudimentaryFix(returnTypeName);
									}
								}  else if (argNum == 6) {
									callingMethod.overload(argList[0], argList[1], argList[2], argList[3], argList[4], argList[5]).implementation = function(a,b,c,d,e,f) {
										rudimentaryFix(returnTypeName);
									}
								} 
							// Go here if overloaded method has a single argument
							} else {
								callingMethod.overload(extractedOverload).implementation = function(a) {
									rudimentaryFix(returnTypeName);
								}
							}
						}
					} else {
						console.log('\x1b[36m[-] Failed to dynamically patch SSLPeerUnverifiedException '+e+'\x1b[0m');
					}
				}
				//console.log('\x1b[36m[+] SSLPeerUnverifiedException hooked\x1b[0m');
				return this.$init(str);
			};
		} catch (err) {
			//console.log('\x1b[36m[-] SSLPeerUnverifiedException not found\x1b[0m');
			//console.log('\x1b[36m'+err+'\x1b[0m');
		}
		


	 
	});
	
}, 0);

 

위 코드의 출처는 아래 github 에서 찾아볼 수 있습니다.

https://gist.github.com/akabe1/5632cbc1cd49f0237cbd0a93bc8e4452

 

Another Android ssl certificate pinning bypass for various methods

Another Android ssl certificate pinning bypass for various methods - frida_multiple_unpinning.js

gist.github.com

 

'경로 및 정보' 카테고리의 다른 글

솔라나 스마트 컨트랙트 만들어보기  (1) 2023.05.08
Ubuntu 20.04 ARM Cross Compile 하기  (0) 2023.05.01
CAN 통신의 개요 (Controller Area Network)  (0) 2023.05.01
pentesting-ftp  (0) 2023.04.22
SBOM 이란  (0) 2023.04.17
블로그 이미지

wtdsoul

,

https://m.blog.naver.com/lagrange0115/221941482740

 

CAN 통신의 개요 (Controller Area Network)

통신은 사람이나 사물 간에 매체를 통하여 정보나 의사를 전달하는 것을 말합니다. 자동차 안에는 수많은 ...

blog.naver.com

 

 

 

 

통신은 사람이나 사물 간에 매체를 통하여 정보나 의사를 전달하는 것을 말합니다. 자동차 안에는 수많은 부품 및 제어기들이 있습니다. 엔진을 제어하는 ECU (Engine Control Unit), 변속기를 제어하는 TCU (Transmission Control Unit), 각종 ADAS (Advanced Driver Assistance System) 관련 제어기 등 수십 개에 해당하는 제어기들이 차량에 장착되고, 제어기들은 서로 데이터를 주고받으며 공유된 정보를 통해 다양한 제어를 하게 됩니다. 데이터를 주고받을 때 제어기들 간의 규칙이 있어야 원활한 통신을 할 수 있는데, 이러한 규칙을 통신 프로토콜 (Protocol)이라고 합니다. 자동차 내에는 CAN (Controller Area Network) 통신, LIN 통신, LAN 통신 등 다양한 통신 방법을 용도에 맞게 사용하고 있습니다. 그중에서 CAN 통신이 자동차에서 가장 많이 사용되고 있습니다.

CAN 통신은 자동차 부품회사인 보쉬 (BOSCH)에서 개발된 차량용 네트워크 통신 방식으로, 전기적 노이즈 발생이 많은 자동차 환경에서 신뢰성을 확보하기 위해 개발된 통신 방식입니다.

CAN 통신은 여러 개의 제어기들을 병렬로 연결하여 데이터를 주고받는 구조로 되어 있습니다. 통신 라인을 공유하는 모든 제어기들이 마스터 역할을 하고 있기 때문에 필요에 따라 언제든지 통신이 가능합니다. 쉽게 말해, 통신선상에 데이터를 띄워 놓으면, 어떤 제어기든지 필요할 때마다 데이터를 가져가 사용하는 방식입니다.

여러 개의 제어기들을 병렬로 연결하여 데이터를 주고받는 구조

제어기 내부의 CAN 통신 회로 구성

제어기 내의 CAN 통신 회로 구성은 위의 블록도와 같습니다. 가장 오른쪽은 외부 CAN BUS로 CAN H와 CAN L 신호를 주고받습니다. CAN BUS는 제어기 커넥터를 통해 연결된 후 CAN 트랜시버로 연결됩니다. 그리고 CAN 트랜시버는 마이크로컨트롤러 (MCU)와 연결됩니다. 정리하면, MCU와 CAN BUS 사이에 CAN 트랜시버가 있는 구조입니다. 그렇다면 CAN 트랜시버의 역할을 간단하게 살펴보겠습니다.

먼저 CAN H와 CAN L의 파형은 아래 그림의 오른쪽과 같습니다. CAN H는 2.5V~3.5V 전압을, CAN L는 2.5V~1.5V 전압을 사용합니다. CAN H와 CAN L의 전위차가 없을 때는 recessive (열성), CAN H와 CAN L의 전위차가 있을 때는 dominant (우성)이라고 표현합니다. 즉, CAN 통신은 두 라인의 전위차를 통해 데이터를 전달하는 것입니다.

 

CAN 통신의 Recessive와 Dominant

CAN BUS의 CAN H와 CAN L 신호가 CAN 트랜시버를 통해 recessive 인지 dominant 인지 판단을 합니다. 그리고 CAN 트랜시버의 RX를 통해 recessive 이면 HIGH, dominant 이면 LOW 신호를 MCU에 전달합니다. 반대로 MCU에서 CAN BUS로 데이터를 전송할 때는 MCU의 LOW와 HIGH 신호를 CAN 트랜시버가 CAN H와 CAN L 신호 형태에 맞게 변환해 줍니다.

출처 : TEXAS INSTRUMENTS, Indtroduction to the Controller Area Network (CAN)

CAN 트랜시버 내부 회로도

위의 CAN 트랜시버 회로와 같이, MCU의 TX에서 HIGH 신호를 보내면 FET는 비활성화되어 2.5V 풀업 저항에 의해 CAN H와 CAN L 모두 2.5V가 됩니다. 반대로 MCU의 TX에서 LOW 신호를 보내면 FET는 활성화되어 CAN H 5V, CAN L는 GND 전위가 됩니다.

CAN 프레임 형식에 대해 간단하게 알아보겠습니다. 바로 아래 그림과 같이 CAN 통신에서 요구하는 CAN 통신 프레임을 만족해야 제어기들 간에 데이터를 전송할 수 있습니다. 쉽게 말해, 서로 데이터를 어떻게 주고받을지 약속을 정하는 것과 같습니다.

CAN 프레임 형식

SOF (Start of Frame)
메시지의 시작을 표시, idle 상태 이후 동기화
Identifier
메시지의 우선순위를 설정, 이진값이 낮을수록 우선순위가 높음
RTR (Remote Transmission Request)
데이터 프레임과 리모트 프레임 구분 (데이터 프레임은 0)
IDE (Idenrifier Extension)
CAN Standard 프레임과 CAN Extended 프레임 구분
R0
Reserved bit
DLC (Data Length Code)
전송 중인 데이터의 바이트 수
Data
8byte 데이터를 전송
CRC (Cycle Redundancy Check)
16bit checksum
ACK (Acknowledgement)
승인
EOF (End of Frame)
CAN 프레임의 끝을 표시
IFS (Interframe Space)
버퍼 영역

CAN 통신은 여러 제어기들이 신호를 함께 보내고, 이를 피드백 받으면서 진행됩니다. 하지만 동시에 여러 제어기들이 신호를 송신한다면 어떻게 우선순위를 정하는지 알아보겠습니다. 아래 표와 같이 NODE 3를 가지고 Idendifier의 비트를 비교합니다.

CAN 통신 arbitration의 원리

신호가 HIGH 이면 recessive, LOW 이면 dominant 입니다. 위의 그림에서 10~6 bit 까지 3개의 NODE 상태는 모두 동일합니다. 5번 bit는 NODE 2만 HIGH (recessive)입니다. Recessive는 말 그대로 "열성"이라는 의미로 여기서부터 NODE 2의 신호 전송은 중지됩니다. 그리고 2번 bit에서는 NODE 1이 HIGH (recessive)입니다. 따라서 NODE 1의 신호 전송이 중지됩니다. 결국 여기서 우선순위는 NODE 3이 가장 높습니다. 중간에 전송을 중지한 NODE 1과 NODE 2는 다음에 재전송을 시도합니다.

※ CAN 통신에서의 에러

에러가 발생되면 에러 프레임이 전송됩니다. 에러 프레임으로 전송 실패를 인식하면 재전송의 기회를 기다립니다.

- BIT 에러 : 송신 bit와 수신 bit가 상이한 경우

- ACK 에러 : 수신 장치가 응답이 없을 때, 통신 선로가 끊기거나 접촉 불량인 경우

- FORMAT 에러 : CRC del, ACK del, EOF 영역에 0 (dominant) 값이 나타난 경우

- STUFF 에러 : Stuffing 규칙이 맞지 않은 경우

- CRC 에러 : CRC가 맞지 않은 경우

CAN 제어기 내부에는 송신 에러 카운터와 수신 에러 카운터가 각각 있습니다. 에러가 검출될 때마다 카운터가 1씩 증가하고, 에러 없이 성공적으로 전달이 완료되면 카운터가 1씩 감소합니다. 초기 상태에는 Error active 상태이며, 에러 카운터 값이 127 보다 커지면 Error passive 상태가 됩니다. 그리고 에러 카운터 값이 255를 초과하면 BUS OFF 상태로 해당 노드를 CAN 망에서 끊어버립니다.

CAN 통신의 에러 상태 처리

'경로 및 정보' 카테고리의 다른 글

Ubuntu 20.04 ARM Cross Compile 하기  (0) 2023.05.01
[frida] 프리다 안드로이드 SSL/TLS 피닝 우회 스크립트  (0) 2023.05.01
pentesting-ftp  (0) 2023.04.22
SBOM 이란  (0) 2023.04.17
Shell code Development pdf  (0) 2023.04.16
블로그 이미지

wtdsoul

,

pentesting-ftp

경로 및 정보 2023. 4. 22. 00:01

https://book.hacktricks.xyz/network-services-pentesting/pentesting-ftp

 

21 - Pentesting FTP - HackTricks

write_enable=YES - Allow commands: STOR, DELE, RNFR, RNTO, MKD, RMD, APPE, and SITE

book.hacktricks.xyz

 

21 - Pentesting FTP

 
Basic Information
The File Transfer Protocol (FTP) is a standard network protocol used for the transfer of computer files between a client and server on a computer network. It is a plain-text protocol that uses as new line character 0x0d 0x0a so sometimes you need to connect using telnet or nc -C.
Default Port: 21
 
PORT STATE SERVICE
 
21/tcp open ftp
Connections Active & Passive
In Active FTP the FTP client first initiates the control connection from its port N to FTP Servers command port – port 21. The client then listens to port N+1 and sends the port N+1 to FTP Server. FTP Server then initiates the data connection, from its port M to the port N+1 of the FTP Client.
But, if the FTP Client has a firewall setup that controls the incoming data connections from outside, then active FTP may be a problem. And, a feasible solution for that is Passive FTP.
In Passive FTP, the client initiates the control connection from its port N to the port 21 of FTP Server. After this, the client issues a passv comand. The server then sends the client one of its port number M. And the client initiates the data connection from its port P to port M of the FTP Server.
Connection debugging
The FTP commands debug and trace can be used to see how is the communication occurring.
Enumeration
Banner Grabbing
 
nc -vn <IP> 21
 
openssl s_client -connect crossfit.htb:21 -starttls ftp #Get certificate if any
Connect to FTP using starttls
 
lftp
 
lftp :~> set ftp:ssl-force true
 
lftp :~> set ssl:verify-certificate no
 
lftp :~> connect 10.10.10.208
 
lftp 10.10.10.208:~> login
 
Usage: login <user|URL> [<pass>]
 
lftp 10.10.10.208:~> login username Password
Unauth enum
With nmap
 
sudo nmap -sV -p21 -sC -A 10.10.10.10
You can us the commands HELP and FEAT to obtain some information of the FTP server:
 
HELP
 
214-The following commands are recognized (* =>'s unimplemented):
 
214-CWD XCWD CDUP XCUP SMNT* QUIT PORT PASV
 
214-EPRT EPSV ALLO* RNFR RNTO DELE MDTM RMD
 
214-XRMD MKD XMKD PWD XPWD SIZE SYST HELP
 
214-NOOP FEAT OPTS AUTH CCC* CONF* ENC* MIC*
 
214-PBSZ PROT TYPE STRU MODE RETR STOR STOU
 
214-APPE REST ABOR USER PASS ACCT* REIN* LIST
 
214-NLST STAT SITE MLSD MLST
 
214 Direct comments to root@drei.work
 
 
FEAT
 
211-Features:
 
PROT
 
CCC
 
PBSZ
 
AUTH TLS
 
MFF modify;UNIX.group;UNIX.mode;
 
REST STREAM
 
MLST modify*;perm*;size*;type*;unique*;UNIX.group*;UNIX.mode*;UNIX.owner*;
 
UTF8
 
EPRT
 
EPSV
 
LANG en-US
 
MDTM
 
SSCN
 
TVFS
 
MFMT
 
SIZE
 
211 End
 
 
STAT
 
#Info about the FTP server (version, configs, status...)
Anonymous login
anonymous : anonymous anonymous : ftp : ftp
 
ftp <IP>
 
>anonymous
 
>anonymous
 
>ls -a # List all files (even hidden) (yes, they could be hidden)
 
>binary #Set transmission to binary instead of ascii
 
>ascii #Set transmission to ascii instead of binary
 
>bye #exit
Automated
Anon login and bounce FTP checks are perform by default by nmap with -sC option or:
 
nmap --script ftp-* -p 21 <ip>
Browser connection
You can connect to a FTP server using a browser (like Firefox) using a URL like:
 
ftp://anonymous:anonymous@10.10.10.98
Note that if a web application is sending data controlled by a user directly to a FTP server you can send double URL encode %0d%0a (in double URL encode this is %250d%250a) bytes and make the FTP server perform arbitrary actions. One of this possible arbitrary actions is to download content from a users controlled server, perform port scanning or try to talk to other plain-text based services (like http).
Download all files from FTP
 
wget -m ftp://anonymous:anonymous@10.10.10.98 #Donwload all
 
wget -m --no-passive ftp://anonymous:anonymous@10.10.10.98 #Download all
Some FTP commands
 
FTPBounce attack
Some FTP servers allow the command PORT. This command can be used to indicate to the server that you wants to connect to other FTP server at some port. Then, you can use this to scan which ports of a host are open through a FTP server.
You could also abuse this behaviour to make a FTP server interact with other protocols. You could upload a file containing an HTTP request and make the vulnerable FTP server send it to an arbitrary HTTP server (maybe to add a new admin user?) or even upload a FTP request and make the vulnerable FTP server download a file for a different FTP server. The theory is easy:
 
Its highly probably that this will throw an error like Socket not writable because the connection doesn't last enough to send the data with RETR. Suggestions to try to avoid that are:
 
 
posts.txt
495KB
Text
posts.txt
 
Filezilla Server Vulnerability
FileZilla usually binds to local an Administrative service for the FileZilla-Server (port 14147). If you can create a tunnel from your machine to access this port, you can connect to it using a blank password and create a new user for the FTP service.
Config files
 
ftpusers
 
ftp.conf
 
proftpd.conf
 
vsftpd.conf
Post-Exploitation
The default configuration of vsFTPd can be found in /etc/vsftpd.conf. In here, you could find some dangerous settings:
 
Shodan
 

'경로 및 정보' 카테고리의 다른 글

[frida] 프리다 안드로이드 SSL/TLS 피닝 우회 스크립트  (0) 2023.05.01
CAN 통신의 개요 (Controller Area Network)  (0) 2023.05.01
SBOM 이란  (0) 2023.04.17
Shell code Development pdf  (0) 2023.04.16
Braktooth-IVI-Report/  (0) 2023.04.14
블로그 이미지

wtdsoul

,

SBOM 이란

경로 및 정보 2023. 4. 17. 10:05

SBOM(SOFTWARE BILL OF MATERIALS) 이란 무엇인가 :: 오픈비 : 삽질은없다 (openbee.kr)

 

SBOM(SOFTWARE BILL OF MATERIALS) 이란 무엇인가

개요 작년 미국의 국가 사이버 보안 강화 지침(2021년 5월)이 배포된 이후, 소프트웨어 산업의 다양한 채널에서 SBOM과 관련한 자문이나 회의가 생기고 있는 상황입니다. 최근의 보안 위협은 공급

openbee.kr

 

개요

작년 미국의 국가 사이버 보안 강화 지침(2021년 5월)이 배포된 이후, 소프트웨어 산업의 다양한 채널에서 SBOM과 관련한 자문이나 회의가 생기고 있는 상황입니다. 

최근의 보안 위협은 공급망, 구축도구, 구축환경, 레파지토리등을 공격하는 추세가 많아지고 있는데 이 지침에서는 미국 연방정부가 사용하는 소프트웨어 공급망의 보안과 무결성을 개선하기 위한 조치를 지시하고 있습니다.

지침이 배포된 이후 미국 정부의 요청으로 미국의 90여개 소프트웨어 기업, 오픈소스 커뮤니티가 자문에 참여하여 의견을 제시히고, CISA, NTIA 에서는 이를 정리하여 SBOM 과 관련한 가이드라인 및 FAQ를 공개하였습니다.

 

SOFTWARE BILL OF MATERIALS | National Telecommunications and Information Administration

A “Software Bill of Materials” (SBOM) is a nested inventory for software, a list of ingredients that make up software components. The following documents were drafted by stakeholders in an open and transparent process to address transparency around sof

www.ntia.gov

 

SBOM 이란?

SBOM 은 SOFTWARE BILL OF MATERIALS 의 약자로 소프트웨어의 구성 요소를 나타내는 메타데이터를 의미하는데 이를 보다 쉽게 설명하자면 우리가 흔히 볼 수 있는 다음과 같은 제품의 성분표기를 떠올리면 됩니다.

성분표기를 통해서 알러지가 있는 사람은 해당 식품을 피하기도 하고, 공급자는 제품의 우수성을 홍보하기도 하고, 크게 성분에 신경쓰지 않고 그냥 사용하는 사용자도 있을 수 있죠.

이와 유사하게, SBOM은 공급되는 소프트웨어의 구성 목록을 잘 표시해서 공급자와 사용자가 이를 기반으로 의사결정에 활용할 수 있는 환경을 조성하는 것을 목표로 하고 있습니다.

NTIA 에서 발표한 SBOM의 필수 구성요소는 다음과 같이 구성되어 있습니다.

 

  • Supplier name
  • Component name
  • Version of the component
  • Cryptograph hash of the component
  • Any other unique identifier
  • Dependency relationship
  • Author of the SBOM data

 

이를 기반으로 작성한다면 다음과 같은 개념도로 표시할 수 있습니다.

National Telecommunications and Information Administration (NTIA) 에서는 오픈소스 소프트웨어나 상용 소프트웨어로 구분하지 않고 모든 공급되는 소프트웨어를 대상으로 광범위하게 적용할 수 있는 SBOM 적용을 위해 산업계의 여러 기업과 커뮤니티에 의견을 청취하고 이를 토대로 SBOM의 이해를 돕는 자료와 적용방법에 대하여 다양한 문서를 배포하고 있으니 아래 문서들을 참고하시기 바랍니다.

 

SPDX, OpenChain

이러한 소프트웨어 구성 목록을 기반으로 공급망의 투명성을 확보해야 한다는 필요성은 오픈소스 커뮤니티에서 10여년 전부터 논의되어 왔으며, 이를 해결하기 위해 실제 산업에서 SPDX와 OpenChain 이 많이 사용되고 있습니다.

  • SPDX는 라이선스 컴플라이언스, 보안 등과 같은 문제를 다루면서 진화해서 현재는 시장에서 가장 성숙한 SBOM으로 자리잡고 있습니다. (https://www.linuxfoundation.org/blog/what-is-an-sbom/)
  • 또한 오픈소스 라이선스 준수를 위한 ISO 국제표준(https://www.iso.org/standard/81039.html) 으로 오픈체인이 있으며, 이는 소프트웨어 공급망의 투명성을 강화하기 위하여 오픈소스 커뮤니티에서 고민하던 결과물입니다.

SBOM이 소프트웨어 보안의 모든 문제를 해결할 수는 없지만 보다 안전한 소프트웨어 사용에 필요한 기본을 제공하는 것은 분명히 필요한 일이며, 다양한 산업계의 의견을 토대로 만들어진 SBOM을 기반으로 소프트웨어 공급망의 투명성을 강화할 수 있는 미국의 이번 정책은 향후 IT 산업과 디지털 인프라의 소프트웨어 관리에 있어서 매우 중요하다고 생각됩니다.

'경로 및 정보' 카테고리의 다른 글

CAN 통신의 개요 (Controller Area Network)  (0) 2023.05.01
pentesting-ftp  (0) 2023.04.22
Shell code Development pdf  (0) 2023.04.16
Braktooth-IVI-Report/  (0) 2023.04.14
Hackers Are Stealing Cars by Injecting Code Into Headlight Wiring  (0) 2023.04.10
블로그 이미지

wtdsoul

,

Shellcode Development.pdf - Google Drive

 

Shellcode Development.pdf

 

drive.google.com

Shellcode Development #2.pdf - Google Drive

 

Shellcode Development #2.pdf

 

drive.google.com

 

 

'경로 및 정보' 카테고리의 다른 글

pentesting-ftp  (0) 2023.04.22
SBOM 이란  (0) 2023.04.17
Braktooth-IVI-Report/  (0) 2023.04.14
Hackers Are Stealing Cars by Injecting Code Into Headlight Wiring  (0) 2023.04.10
ASPICE 개요  (0) 2023.04.03
블로그 이미지

wtdsoul

,

Braktooth Hunting in the Car Hacker's Wonderland (rollingpwn.github.io)

 

Braktooth Hunting in the Car Hacker's Wonderland

INTRODUCTION Years ago, a team of researchers at SUTD (Asset-Group) discovered and disclosed the family of vulnerabilities in the classic Bluetooth link manager layer. They've released a paper and POC named "Braktooth: Causing Havoc on Bluetooth link manag

rollingpwn.github.io

 

INTRODUCTION

Years ago, a team of researchers at SUTD (Asset-Group) discovered and disclosed the family of vulnerabilities in the classic Bluetooth link manager layer. They've released a paper and POC named "Braktooth: Causing Havoc on Bluetooth link manager" The paper is very detailed and enjoyable to read. I highly recommend it to anyone into Bluetooth security. The Braktooth is a codename for 16 classic Bluetooth vulnerabilities. It will cause affect BT devices continuously crash or deadlock. Furthermore, at least in one case, attackers can remotely execute arbitrary code and erase all the data on the targeted devices. These bugs are present in various BT Chipsets across many manufacturers such as Intel, Qualcomm, TI, Infineon, etc.

Since my main interest focused on vehicle security, after reading through the Braktooth paper, one thing immediately got my attention. They mentioned in the paper, Braktooth not only affects laptops, and smartphones but also Infotainment units in Automobiles, even the audio system in airplanes is affected. For IVIs, they listed the Volvo FH as an example in the paper. This got me wondering if any other popular cars out there are also affected by Braktooth.

FIRST-BLOOD

Before we jump on the cars, we need to get familiar with Braktooth. The actual environment is quite simple to set it up. In the paper, they mentioned some Chipset from Mediatek that are affected. My laptop Lenovo L14 happened to use the Ralink chipset for Bluetooth communication. Since Ralink is part of the Mediatek group, which make it is the perfect target for the test run.


Because there are 16 POCs from the Braktooth vulnerabilities, we've to go through all of them. And we found one of the vulnerabilities called Invalid-Timing-Accuracy almost always work. The vulnerable chipsets do not properly handle the reception of a malformed LMP timing accuracy response followed by multiple re-connections to the target link slave.

This allows attackers to exhaust device BT resources. The attacker can trigger a crash or disturb other BT devices connected to the target chipset. The best part is attacker only needs to know the BDAddress of the target device. No authentication is required to launch the attack. As the video below demonstrated, the Bluetooth connection between the laptop and speaker stop functioning and eventually disconnected the connection.

INVESTIGATION

People always ask us how can Star-V Lab access so many cars. And this project is a perfect chance to show how we achieved it. The easiest place to start would be for the Car components to sit on the test bench table. For example, we happened to have a 2nd hand Nissan IVI in the lab. As we can see, after we fired the Invalid-Timing-Accuracy POC, the Nissan IVI kind of frozen, and it won't detect any Bluetooth devices nearby anymore.

The 2nd place to look for potential targets is the company car parking lot. If we ask nicely, most of the staff even the company CEO are interested to see if their car can hacked ;) At that time, we got 2 Tesla cars and 1 Changan Uni-T accessible for testing. For Tesla Model 3 and Model X, only the Invalid-Setup-Complete POC worked. All other POCs failed.

 

But for Changan Uni-T almost all the vulns works. Only 6 of the POC has no impaction. As the video shows, Braktooth disconnected the connection. Interestingly the Bluetooth logo on the IVI screen still shows everything is fine, but in fact, the connection has been disconnected.

If we got enough budget we can rent some cars for testing. But what if our budget is short and we need to test the latest modern cars? An advantage of living in a big city is we are surrounded by Car dealer shops. And these are perfect spots for us.

This time we found 4 cars affected by Braktooth. The first one is NIO ET5, which is a Chinese brand and quite popular in China.

For NIO it will disconnect the Bluetooth connection straight away.

Then we went to the Volkswagen to test ID4X. Compare to other Android-based IVI, ID4X seems a bit hard to use.

Again once we fired the attack, the Bluetooth connection disconnected.

Finally, we tested a new smart car player in the Chinese market called ARCFOX. As the video shows the music start been funny after we fired the attack.

One thing special regarding this brand is one of the car models using the Huawei HarmonyOS as IVI's system.

However, when coming to low-level Bluetooth attack, Huawei HarmonyOS makes no difference.

Another nice spot for testing is the Car exhibition. The good thing about the exhibition is we may able to test some fancy sports cars, which normally we won't be able to touch.

Here we've tested the Neta V and Leapmotor C01 cars.


As we can see both of them experienced the disturb first then the connection disconnected completely.

FINAL-FHOUGHT

As whitehat security researchers, we like to follow the responsible disclosure procedure. Unfortunately unlike the Internet companies, most car companies still live in a stone age. They neither don't have a bounty program nor contact info for reporting bugs. Therefore, we filed a report to their customer service and hope someone can see it. But we like to give a thumbup to the Tesla and NIO. These two companies have set up bug bounty programs and given a very quick response to our bug report. However, Nio replied that this bug has out of their scope.

And Tesla thinks this is not a security issue, since the braktooth was only able to cause the Tesla Bluetooth audio jitters. We kind of agreed on this point, so let's continue our journey and digging deeper. Spoiler alert, we did find other issues on some of those IVIs above. And at least caused one of the fancy car's IVI to go black screen. Stay tuned for our future report ;)

 

 

블로그 이미지

wtdsoul

,

Hackers Are Stealing Cars by Injecting Code Into Headlight Wiring (thedrive.com)

 

Hackers Are Stealing Cars by Injecting Code Into Headlight Wiring

High-tech thieves are stealing cars using a device that injects CAN messages into a vehicle's headlight harness.

www.thedrive.com

https://kentindell.github.io/2023/04/03/can-injection/

 

CAN Injection: keyless car theft

This is a detective story about how a car was stolen - and how it uncovered an epidemic of high-tech car theft. It begins with a tweet. In April 2022, my friend Ian Tabor tweeted that vandals had been at his car, pulling apart the headlight and unplugging

kentindell.github.io

Once the device is on and plugged in, it wakes up the CAN network by sending a frame—similar to if you were to pull on a door handle, approach with a passive entry key, or hit a button on your fob. It then listens for a specific CAN message to begin its attack. The device then emulates a hardware error which tricks other ECUs on the CAN network to stop sending messages so that the attacking device has priority to send its spoofed messages to CAN devices.

 

The pause of valid messages is when the device is able to go into attack mode. It then sends the spoofed "valid key present" messages to the gateway which makes the car think that an actual valid key is being used to control the vehicle. Next, the attacker simply presses the speaker's "play" button, and the car's doors are unlocked.

Given that the manufacturer of these CAN injection devices claims that the devices are so effective against a myriad of makes and models, it would seem that this could be an industry-wide problem that may take some brainstorming to fix.

The good news is that this type of attack can be thwarted. While there are quick-and-dirty methods that could potentially be re-defeated in the long run, an automaker looking to prevent this type of attack by encrypting its CAN Bus network. According to Tindell, Canis is working on a similar project to retrofit U.S. military vehicles with a similar encryption scheme, similar to what he suggests as the fix for commercial vehicles experiencing this issue.

If thieves are already exploiting this in the wild (which they are), it means that it's already a problem. And if it continues to grow in popularity, perhaps it could lead to a repeat of what Hyundai and Kia are currently experiencing on a significantly more low-tech level.

'경로 및 정보' 카테고리의 다른 글

Shell code Development pdf  (0) 2023.04.16
Braktooth-IVI-Report/  (0) 2023.04.14
ASPICE 개요  (0) 2023.04.03
ISO 26262 ASIL D 와 IEC 61508 SIL 3 인증 획득한 RTOS  (0) 2023.04.03
XSS 우회 패턴 등  (0) 2023.03.20
블로그 이미지

wtdsoul

,