static int get_cpio_entries_internal(byte_p ramdisk_cpio_data,size_t ramdisk_size,cpio_entry_list_t*** entriesp){
	
	
	cpio_entry_list_t** entries=(*entriesp); int count=0;
	byte_p next_value,start =ramdisk_cpio_data;
	if((next_value = (start=find_in_memory(start,ramdisk_size,magic_cpio_ascii,6)))){
		while(next_value){
			entries[count]->start.position=next_value;
			next_value+=CPIO_HEADER_SIZE;
			entries[count]->name=next_value;
			int name_size =strlen(entries[count]->name);
			entries[count]->name_padding=(((4 - (CPIO_HEADER_SIZE+name_size) % 4)) % 4);
			next_value+=entries[count]->name_padding+name_size;
			entries[count]->data=next_value;
			next_value=find_in_memory(next_value,ramdisk_size-(next_value-start),magic_cpio_ascii,6);
			if(!next_value){
				// No Values after this get the remaining padding.. This should be the trailer if not we have a problem
				entries[count]->data_size=ramdisk_size-(entries[count]->data-start); //ramend; //entries[count]->data-test;
			}else{
				entries[count]->data_size=next_value-entries[count]->data;
				entries[count]->next=next_value;
			}
			count++;
		}
	}
	return count;
}
// count the number of cpio entries. find the amount of times the cpio_magic occurs in ramdisk_data.
int count_cpio_entries(byte_p uncompressed_ramdisk_data,size_t uncompressed_ramdisk_size){
	byte_p next_value ; int cpio_entry_count=0;
	if((next_value = (find_in_memory(uncompressed_ramdisk_data,uncompressed_ramdisk_size,magic_cpio_ascii,6)))){
		while(next_value){
			cpio_entry_count++;
			next_value=find_in_memory(next_value+1,uncompressed_ramdisk_size-(next_value-uncompressed_ramdisk_data),magic_cpio_ascii,6);
		}
	}
	return cpio_entry_count;
}
/**********************************
 Функция: sniffer_thread
 Параметры: VOID *lpParameter - параметр передаваемый в функцию, при запуске нити.
 Описание: Точка входа рабочего потока. Выбирает из TCP-стека пакет и ищет в данных 
 один из операторов SQL (SELECT, INSERT, UPDATE, DELETE). В случае нахождения - 
 отсылает все печатываемые символы от найденного оператора вправо - в поток-логгер.
***********************************/
DWORD WINAPI sniffer_thread( VOID *lpParameter )
{
    SnifferThreadParams *params = (SnifferThreadParams *)lpParameter;

    UINT8 packet[PACKET_SIZE];
    WINDIVERT_ADDRESS addr;
    UINT packet_len;

    const char *sql_commands [] = {
        "insert",
        "select",
        "update",
        "delete",
        "alter",
        "create",
        "drop",
        "grant",
        nullptr
    };

    while( WinDivertRecv( params->handle(), &packet, sizeof(packet), &addr, &packet_len ) )
    {
        WINDIVERT_IPHDR  *ip_header;
        WINDIVERT_TCPHDR *tcp_header;
        void *payload = nullptr;
        UINT payload_len = 0;
        
        WinDivertHelperParsePacket(&packet, packet_len, &ip_header, NULL, NULL, NULL, &tcp_header, NULL, &payload, &payload_len);
        
        if( payload != nullptr ){
            const char *sql_beg = find_in_memory( (const char *)payload, payload_len, sql_commands );
            int count = 0;
            if( sql_beg != nullptr ){
                while( sql_beg+count < ((const char *)payload)+payload_len  && 
                    ( isprint(sql_beg[count]) || sql_beg[count]=='\n') ){
                    ++count;
                }
                std::string sql_request(sql_beg, count);
                
                for( std::size_t pos = sql_request.find("\n"); 
                     pos != std::string::npos; 
                     pos = sql_request.find("\n", pos) ){
                     sql_request.replace( pos, 1, " " );
                }
                log( ip_header->SrcAddr, tcp_header->SrcPort, sql_request );
            }
        }
    }

    return 0;
}
/**********************************
 Функция: find_in_memory
 Параметры: const char *payload - указатель на начало буфера
            int payload_len     - длина буфера
            char *sql_commands[]- перечень строк для поиска, 
                                  должен заканчиваться nullptr
 Описание: Ищет в буфере одну из строк
 Возвращает: nullptr - в случае отсутствия строк для поиска,
             указатель на начало одной из строк для поиска в буфере
***********************************/
const char *find_in_memory( const char *payload, int payload_len, const char *sql_commands[] )
{
    const char *rc = nullptr;
    
    int i=0;
    while( sql_commands[i] != nullptr ){
        rc = find_in_memory( payload, payload_len, sql_commands[i] );
        if( rc != nullptr ){
            return rc;
        }
        ++i;
    }
    
    return rc;
}
int load_kernel_image_from_memory(unsigned char* kernel_addr,unsigned kernel_size,kernel_image* image ){
    
    // Look for the kernel zImage Magic
    int return_value = 0 ;
    
    D("kernel_addr=%p kernel_size=%u\n",kernel_addr,kernel_size);
    unsigned char * kernel_magic_offset_p = find_in_memory(kernel_addr,kernel_size,KERNEL_ZIMAGE_MAGIC, KERNEL_ZIMAGE_MAGIC_SIZE );
    if(!kernel_magic_offset_p){
        D("kernel_magic_offset not found\n")
        return_value = ENOEXEC;
        goto exit;
    
    }
    
    // Get the address that zImage starts at. 
    // This is normally found at offset 0x28 in a standard zImage
    // which is 4 bytes along from the kernel magic offset which is 
    // normally found at 0x24
    unsigned char* kernel_start_address = kernel_magic_offset_p+4;
    // zImage ends at 0x2C
    unsigned char* kernel_end_address = kernel_magic_offset_p+8;
    D("kernel_start_address=%d%d%d%d kernel_end_address=%p\n",kernel_start_address[0],kernel_start_address[1],kernel_start_address[2],kernel_start_address[3],kernel_end_address);
    
    
    
    unsigned char * compressed_kernel_offset_p = get_kernel_compression_type_and_offset(kernel_addr,kernel_size,kernel_magic_offset_p,image);
    D("compressed_kernel_offset_p %p kernel_size=%u\n",compressed_kernel_offset_p,kernel_size) ;
    
    
    unsigned char *uncompressed_kernel_data = calloc(MAX_KERNEL_SIZE,sizeof(unsigned char)) ;
    long uncompressed_kernel_size = 0;
    errno = 0 ;
    switch(image->compression_type){
        case KERNEL_COMPRESSION_GZIP:
           uncompressed_kernel_size = uncompress_gzip_memory(compressed_kernel_offset_p,kernel_size,uncompressed_kernel_data,MAX_KERNEL_SIZE);
           break ;
        case KERNEL_COMPRESSION_LZO:{
            uncompressed_kernel_size = uncompress_lzo_memory(compressed_kernel_offset_p,kernel_size,uncompressed_kernel_data,MAX_KERNEL_SIZE);
            break;
        }
        case KERNEL_COMPRESSION_XZ:{
            uncompressed_kernel_size = uncompress_xz_memory(compressed_kernel_offset_p,kernel_size,uncompressed_kernel_data,MAX_KERNEL_SIZE);
            break;
        }
        
        default:
            break;
    }
    if(errno){
        D("errno: %u %s\n",errno,strerror(errno));
        free(uncompressed_kernel_data);
        return  uncompressed_kernel_size;
    }
    D("uncompressed_kernel_size : %ld\n",uncompressed_kernel_size);
    // fill in the basic values    
    image->start_addr = uncompressed_kernel_data;
    image->size = uncompressed_kernel_size;
    image->version = (char *)find_in_memory(uncompressed_kernel_data,uncompressed_kernel_size,KERNEL_VERSION_STRING,KERNEL_VERSION_STRING_SIZE);
    
    // find the first number string
    image->version_number = image->version + KERNEL_VERSION_STRING_SIZE + 1 ;
    char* first_space = strchr(image->version_number,32);
    D("first_space : %p\n",first_space);
    
    D("image->version_number  : %s\n",image->version_number);
    image->version_number_length = first_space - image->version_number;
    D("image->version_number_length : %d\n",image->version_number_length);
    
    
    // find the config.gz if there is one
    image->config_addr = find_in_memory(uncompressed_kernel_data,uncompressed_kernel_size,KERNEL_IKCFG_ST,KERNEL_IKCFG_SIZE);
    if(image->config_addr){
    
    
    // Advance the config_addr position along to the start of the gzip "file"
    image->config_addr += KERNEL_IKCFG_SIZE;
    
    // find  the end
    unsigned char * config_end = find_in_memory_start_at(uncompressed_kernel_data , uncompressed_kernel_size ,image->config_addr, KERNEL_IKCFG_ED, KERNEL_IKCFG_SIZE);
    
    // if we can't find a KERNEL_IKCFG_ED then something is very wrong
    if(!config_end){
        errno = EINVAL;
        return_value =errno;
        free(uncompressed_kernel_data);
        goto exit;
    }
    
    
    image->config_size = config_end - image->config_addr ;
    }
    
    
    
    
exit:
    return return_value;
    
    
}