SCSI Read(10) on a Physical Drive on Windows - c

I tried issuing a SCSI Read(10) command to a physical drive on a Windows 7 machine. Below is the code snippet that I am using. It is failing with error code 87.
void scsi_read()
{
const UCHAR cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 512, 0 };
UCHAR buf[512];
BYTE senseBuf[196];
const int SENSE_LENGTH = 196;
LPCSTR fname = "\\\\.\\E:";
HANDLE fh;
DWORD ioctl_bytes;
DWORD err = 0;
SCSI_PASS_THROUGH s = {0};
memcpy(s.Cdb, cdb, sizeof(cdb));
s.CdbLength = 10;
s.DataIn = SCSI_IOCTL_DATA_IN;
s.TimeOutValue = 30;
s.Length = sizeof(SCSI_PASS_THROUGH);
s.ScsiStatus = 0x00;
s.SenseInfoOffset = senseBuf;
s.SenseInfoLength = SENSE_LENGTH;
s.DataBufferOffset = buf;
s.DataTransferLength = 512;
fh = CreateFile("\\\\.\\E:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if(fh == INVALID_HANDLE_VALUE) {
printf("Could not open %s file, error %d\n", fname, GetLastError());
return (FALSE);
}
int ret = DeviceIoControl(fh,IOCTL_SCSI_PASS_THROUGH, &s,sizeof(s), //scsiPassThrough.sizeof,
&s,
sizeof(s),
&ioctl_bytes,
NULL);
printf("ret %d",(int)ret);
if (ret==1) {
printf("OK");
}
else {
err = GetLastError();
printf("Last error code %u\n", err);
printf("Return size %d\n", ioctl_bytes);
printf("Sense data\n");
int i=0;
for (i = 0; i < 20; i++) {
printf("\t%x", senseBuf[i]);
}
printf("\n");
}
CloseHandle(fh);
}
Error: Hex dumps are printed in the output

you got error code 87 - ERROR_INVALID_PARAMETER because code totally wrong.
for example:
const UCHAR cdb[10] = { 0x28, 0, 0, 0, 0, 0, 0, 0, 512, 0 };
but 512 is > 255 (MAXUCHAR) are you not got compiler warning here ?
warning C4305: 'initializing': truncation from 'int' to 'const UCHAR'
look at this line !
s.DataBufferOffset = buf;
from SCSI_PASS_THROUGH structure:
DataBufferOffset
Contains an offset from the beginning of this structure to the data
buffer. The offset must respect the data alignment requirements of the
device.
so offset to buffer, not pointer to buffer
for use this correct you code need be like this:
struct MY_DATA : SCSI_PASS_THROUGH
{
UCHAR buf[512];
} s;
s.DataBufferOffset = FIELD_OFFSET(MY_DATA, buf);
but better use SCSI_PASS_THROUGH_DIRECT with IOCTL_SCSI_PASS_THROUGH_DIRECT
you hardcode sector size (512), when need get it at runtime. and how you initialize CDB ?!? at all unclear what you try todo.
working code example (sorry but on c++ instead c)
#define _NTSCSI_USER_MODE_
#include <scsi.h>
#include <ntddscsi.h>
BOOL scsi_read(HANDLE fh, PVOID buf, DWORD cb, ULONGLONG LogicalBlock, ULONG TransferBlocks)
{
SCSI_PASS_THROUGH_DIRECT s = {
sizeof(SCSI_PASS_THROUGH_DIRECT), 0, 0, 0, 0, 0, 0, SCSI_IOCTL_DATA_IN, cb, 30, buf
};
union {
PUCHAR Cdb;
CDB::_CDB10* Cdb10;
CDB::_CDB16* Cdb16;
};
Cdb = s.Cdb;
if (MAXULONG < LogicalBlock || MAXUSHORT < TransferBlocks)
{
s.CdbLength = sizeof(CDB::_CDB16);
Cdb16->OperationCode = SCSIOP_READ16;
*(ULONGLONG*)Cdb16->LogicalBlock = _byteswap_uint64(LogicalBlock);
*(ULONG*)Cdb16->TransferLength = _byteswap_ulong(TransferBlocks);
}
else
{
s.CdbLength = sizeof(CDB::_CDB10);
Cdb10->OperationCode = SCSIOP_READ;
*(ULONG*)&Cdb10->LogicalBlockByte0 = _byteswap_ulong((ULONG)LogicalBlock);
*(USHORT*)&Cdb10->TransferBlocksMsb = _byteswap_ushort((USHORT)TransferBlocks);
}
DWORD ioctl_bytes;
return DeviceIoControl(fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, &s, sizeof(s), &s, sizeof(s), &ioctl_bytes, NULL);
}
BOOL test_scsi_read(PCWSTR fname)
{
BOOL fOk = FALSE;
HANDLE fh = CreateFileW(fname, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (fh != INVALID_HANDLE_VALUE)
{
DWORD ioctl_bytes;
DISK_GEOMETRY_EX dg;
if (DeviceIoControl(fh, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &dg, sizeof(dg), &ioctl_bytes, 0))
{
// 16 sectors for example
ULONG cb = 16 * dg.Geometry.BytesPerSector;
if (PVOID buf = new CHAR[cb])
{
// read first 16 sectors
fOk = scsi_read(fh, buf, cb, 0, 16);
if (ULONGLONG LogicalBlock = dg.DiskSize.QuadPart / dg.Geometry.BytesPerSector)
{
// read last sector
fOk = scsi_read(fh, buf, dg.Geometry.BytesPerSector, LogicalBlock - 1, 1);
}
delete buf;
}
}
CloseHandle(fh);
}
return fOk;
}
test_scsi_read(L"\\\\?\\e:");

Related

wolfcryp RSA Parse Key Segmentation Failed

Am trying to verify a message using RSA public key with help of WolfCrypt library. The message signing and verification is done using Openssl is successful with below commands.
openssl dgst -sha256 -sign private.pem -out Message.sign.rsa1024-sha-256 Message.txt
openssl dgst -sha256 -verify public.der -signture Message.sign.rsa1024-sha-256 Message.txt
Now, while trying to write a program using WolfCrypt library to verify the message(the program is not complete, Am stuck at parse public key part), the program is raising segmentation fault while parsing the public key itself. However, while trying to debug the program using GDB, the parse key section of code executes does not raise any segmentation fault and going to next step and exiting normally.
To avoid segfault, I tried malloc instead, still getting alloc(): memory corruption error.
It looks like the problem lies in wc_RsaPublicKeyDecode parameters. on GDB, while step-in to this function, the parameters looks empty. Any suggestion is welcome.
#include <stdio.h>
#include <stdlib.h>
/* Import APIs for Signing and Verification */
#include "wolfssl/wolfcrypt/rsa.h"
#include "wolfssl/wolfcrypt/hash.h"
#include "wolfssl/wolfcrypt/signature.h"
/* Import WolfSSL Types */
#include "wolfssl/wolfcrypt/types.h"
typedef struct wrap_Key
{
word32 _KeyIndex;
RsaKey _RsaKey;
}Key_t;
typedef struct wrap_Signature
{
/* Signature Algorithms */
enum wc_SignatureType _TYPE;
enum wc_HashType _DIGEST;
/* Message & Signature */
byte *_Message;
word32 _MessageLength;
byte *_Signature;
word32 _SignatureLength;
byte *_KeyBuffer;
word32 _KeyBufferLength;
/* RSA Key Structure */
Key_t _PKCS;
}Signature_t;
static int wrap_ReadFileToBuffer( byte **BufferData, word32* BufferLength, byte* URI )
{
int ret = EXIT_SUCCESS;
FILE *file = NULL;
file = fopen(URI, "r");
if( NULL == file )
{
printf( "Error! Unable to stat file.\r\n" );
return EXIT_FAILURE;
}
/* Get content length & Reset Cursor */
fseek( file, 0, SEEK_END );
*BufferLength = (word32) ftell(file);
fseek( file, 0, SEEK_SET );
/* Allocate Enough Buffer */
*BufferData = (byte*)(malloc( *BufferLength ));
if( NULL == *BufferData )
{
fclose(file);
printf("Error! Memory Allocation Failed.\r\n");
return EXIT_FAILURE;
}
/* Read File Content */
if( ( ret = fread( *BufferData, 1, *BufferLength, file ) )
!= *BufferLength )
{
fclose(file);
printf("Error! Unable to read file.\r\n");
return EXIT_FAILURE;
}
fclose(file);
return ret;
}
Signature_t *RSA1;
int main()
{
int ret = EXIT_SUCCESS;
RSA1 = malloc(sizeof(Signature_t));
/* Define Signagure & Type */
RSA1->_TYPE = WC_SIGNATURE_TYPE_RSA;
RSA1->_DIGEST = WC_HASH_TYPE_SHA256;
/* Initialize Message & Signature */
RSA1->_Message = NULL;
RSA1->_Signature = NULL;
/* Verify does the Hash given above is supproted? */
if( wc_HashGetDigestSize( RSA1->_DIGEST ) <= 0 )
{
printf("Hash type %d not supported!\n", RSA1->_DIGEST);
return EXIT_FAILURE;
}
if( wrap_ReadFileToBuffer( &(RSA1->_Message),
&(RSA1->_MessageLength), "Message.txt" ) <= 0 )
{
printf("Error! Reading Message Failed.\r\n");
return EXIT_FAILURE;
}
if( wrap_ReadFileToBuffer( &(RSA1->_Signature),
&(RSA1->_SignatureLength),
"Message.sign.rsa1024-sha-256" ) <= 0 )
{
printf("Error! Reading Signature Failed.\r\n");
return EXIT_FAILURE;
}
if( wrap_ReadFileToBuffer( &(RSA1->_KeyBuffer), &(RSA1->_KeyBufferLength),
"public.der" ) <= 0 )
{
printf("Error! Reading Key Failed.\r\n");
return EXIT_FAILURE;
}
if( ( ret = wc_InitRsaKey( &(RSA1->_PKCS._RsaKey), NULL ) ) )
{
printf("Error! Initialize Key Failed: -%d.\r\n", -ret);
return EXIT_FAILURE;
}
RSA1->_PKCS._KeyIndex = 0;
if( ( ret = wc_RsaPublicKeyDecode( RSA1->_KeyBuffer,
&RSA1->_PKCS._KeyIndex,
&RSA1->_PKCS._RsaKey,
RSA1->_KeyBufferLength ) ) )
{
printf("Error! Reading Key Failed: -%d.\r\n", -ret);
return EXIT_FAILURE;
}
free(RSA1);
printf("WolfCrypt - Sample program!\r\n");
return ret;
}
While trying to debug using GDB, found that after wc_InitRsaKey function, the entire structure *RSA1 is getting char array(byte here) is missing it's data.
(gdb) p *RSA1
$43 = {_TYPE = WC_SIGNATURE_TYPE_RSA, _DIGEST = WC_HASH_TYPE_SHA256,
_Message = 0x5555557585d0 "This is sample message to be signed!\n", _MessageLength = 37,
_Signature = 0x555555758600 "$\372\324#\340M\353\"\216\226\302V\372\265\210\242\377\362\343ɮ\032\021\206K\016/\f2\002\020!\274\234\024\212,\034\276\276,31\217\277\274sP\341c\024=u\236\233l\207\330\320>Ė\300K\211]\325\322x\307_9\251\017#\021&apos;\225Oƞ\276\311\a\177\063`\016\271G8\r;\201\036,7x\246\251Wd\246j\273\272\220\304\354\244\305\370\027\321\312\017\250n\336&apos;\375v{\251\267\270\237M", _SignatureLength = 128,
_KeyBuffer = 0x555555758690 "0\201\237\060\r\006\t*\206H\206\367\r\001\001\001\005",
_KeyBufferLength = 162, _PKCS = {_KeyIndex = 0, _RsaKey = {n = {used = 0, alloc = 0,
sign = 0, dp = 0x0}, e = {used = 0, alloc = 0, sign = 0, dp = 0x0}, d = {used = 0,
alloc = 0, sign = 0, dp = 0x0}, p = {used = 0, alloc = 0, sign = 0, dp = 0x0}, q = {
used = 0, alloc = 0, sign = 0, dp = 0x0}, dP = {used = 0, alloc = 0, sign = 0,
dp = 0x0}, dQ = {used = 0, alloc = 0, sign = 0, dp = 0x0}, u = {used = 0, alloc = 0,
sign = 0, dp = 0x0}, heap = 0x0, data = 0x0, type = 0, state = 0, dataLen = 0,
dataIsAlloc = 0 &apos;\000&apos;}}}
(gdb) n
133 RSA1->_PKCS._KeyIndex = 0;
(gdb) p *RSA1
$44 = {_TYPE = WC_SIGNATURE_TYPE_RSA, _DIGEST = WC_HASH_TYPE_SHA256,
_Message = 0x5555557585d0 "", _MessageLength = 37, _Signature = 0x555555758600 "",
_SignatureLength = 128, _KeyBuffer = 0x555555758690 "", _KeyBufferLength = 162, _PKCS = {
_KeyIndex = 0, _RsaKey = {n = {used = 0, alloc = 0, sign = 0, dp = 0x0}, e = {used = 0,
alloc = 0, sign = 0, dp = 0x0}, d = {used = 0, alloc = 0, sign = 0, dp = 0x0}, p = {
used = 0, alloc = 0, sign = 0, dp = 0x0}, q = {used = 0, alloc = 0, sign = 0,
dp = 0x0}, dP = {used = 0, alloc = 0, sign = 0, dp = 0x0}, dQ = {used = 0, alloc = 0,
sign = 0, dp = 0x0}, u = {used = 0, alloc = 0, sign = 0, dp = 0x0}, heap = 0x0,
data = 0x0, type = 0, state = 0, dataLen = 0, dataIsAlloc = 0 &apos;\000&apos;}}}
#Gopi,
The most common cause of such a segmentation fault is a misconfiguration of application and library. The first thing to check is the headers included.
/* Import APIs for Signing and Verification */
#include "wolfssl/wolfcrypt/rsa.h"
#include "wolfssl/wolfcrypt/hash.h"
#include "wolfssl/wolfcrypt/signature.h"
/* Import WolfSSL Types */
#include "wolfssl/wolfcrypt/types.h"
Notice that neither "wolfssl/options.h" or "wolfssl/wolfcrypt/settings.h" was included. If you built the wolfSSL library with ./configure && make please include "wolfssl/options.h" before all other wolfSSL headers. If you are only using "wolfssl/wolfcrypt/settings.h" to control the build and options.h is not found then at least include "wolfssl/wolfcrypt/settings.h" before all other wolfSSL headers:
/* Import APIs for Signing and Verification */
#include <wolfssl/options.h> // If not found or not available then include <wolfssl/wolfcrypt/settings.h>
#include "wolfssl/wolfcrypt/rsa.h"
#include "wolfssl/wolfcrypt/hash.h"
#include "wolfssl/wolfcrypt/signature.h"
/* Import WolfSSL Types */
#include "wolfssl/wolfcrypt/types.h"
Cheers,
K

receive ip frames using ndisuio

I'm writing a DHCP client for Windows ce. after doing it all with sockets I realized that I coudn't send packets from ip 0.0.0.0 so I found that I need to use NDISUIO.
After googling about NDISUIO I can send working DHCP Discovery Packets BUT I can't receive the server response ( the program gets stuck waiting for packets). Note that I can see them in wireshark.
int cUDP::Start()
{
char MensajeLog[256];
char buff[1024];
TCHAR pDevName[1024];
TCHAR pDevBuf[1024];
PNDISUIO_QUERY_BINDING pQueryBinding;
ULONG ulData;
NDISUIO_SET_OID set_oid;
//NDISUIO_QUERY_OID query_oid;
//El ethernet type para el protocolo IP es 0x0800
USHORT uEther =0x0800;
//###########################################################
if(m_hAdapter == INVALID_HANDLE_VALUE)
m_hAdapter = CreateFile(
NDISUIO_DEVICE_NAME,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
INVALID_HANDLE_VALUE);
if(m_hAdapter == INVALID_HANDLE_VALUE || m_hAdapter == NULL)
{
m_iLastError = CUDP_SOCKET_ERROR;
return 1;
}
pQueryBinding = (PNDISUIO_QUERY_BINDING) buff;
pQueryBinding->BindingIndex = 0;
if(!DeviceIoControl( m_hAdapter,
IOCTL_NDISUIO_QUERY_BINDING,
pQueryBinding,
sizeof(NDISUIO_QUERY_BINDING),
NULL,
1024,
&m_dwReturnedBytes,
NULL))
{
CloseHandle(m_hAdapter);
return 2;
}
else
{
memset(pDevName,0,1024);
memcpy(pDevName,&buff[pQueryBinding->DeviceNameOffset], pQueryBinding->DeviceNameLength);
}
if(!DeviceIoControl( m_hAdapter,
IOCTL_NDISUIO_OPEN_DEVICE,
pDevName,
wcslen(pDevName)*sizeof(TCHAR),
NULL,
0,
&m_dwReturnedBytes,
NULL))
{
CloseHandle(m_hAdapter);
return 3;
}
if(!DeviceIoControl( m_hAdapter,
IOCTL_NDISUIO_SET_ETHER_TYPE,
&uEther,
sizeof(uEther),
NULL,
0,
&m_dwReturnedBytes,
NULL))
{
CloseHandle(m_hAdapter);
return 5;
}
ulData = NDIS_PACKET_TYPE_ALL_LOCAL|NDIS_PACKET_TYPE_BROADCAST|NDIS_PACKET_TYPE_PROMISCUOUS;
set_oid.Oid = OID_GEN_CURRENT_PACKET_FILTER;
CopyMemory(&set_oid.Data[0], &ulData,sizeof(ulData));
set_oid.ptcDeviceName = pDevName;
if(!DeviceIoControl( m_hAdapter,
IOCTL_NDISUIO_SET_OID_VALUE,
&set_oid,
sizeof(set_oid),
NULL,
0,
&m_dwReturnedBytes,
NULL))
{
CloseHandle(m_hAdapter);
return 6;
}
return 0;
};
int cUDP::ReceiveFrame ( BYTE* pBuffer,
DWORD Timeout_ms )
{
int timeout;
int timepoint;
DWORD pdwReadBytes;
socklen_t SendAddrlen = sizeof(m_SendAddr);
int BufferLen = sizeof(IPHeaderFormat) +
sizeof(UDPHeaderFormat) +
sizeof (DHCPMsgFormat);//sizeof (DHCPMsgFormat);
timepoint = GetTickCount();
do
{
timeout = GetTickCount();
{
if(!ReadFile( m_hAdapter,
pBuffer,
0,
NULL,
NULL))
{
m_iLastError = CUDP_RECEIVING_ERROR;
}
}
}while(((unsigned) (timeout - timepoint) < Timeout_ms));
return m_iLastError;
};
Anyone can push me in the right direction? thanks in advance
After reading and searching a lot, I found that the problem was on the call to DeviceIoControl with IOCTL_NDISUIO_SET_ETHER_TYPE. It turns out that uEther must be in network byte order so changing this variable to uEther = 0x0008; will do the trick.

How to extend a volume programmatically

My requirement is to extend drive volume through program. When I used IOCTL_DISK_GROW_PARTITION in DeviceIO to extend it, the disk management shows the new modified size while the size of the drive in This PC (My Computer) remains unchanged.
BOOL DeviceIoControl(
(HANDLE) hDevice, // handle to device
IOCTL_DISK_GROW_PARTITION, // dwIoControlCode
(LPVOID) lpInBuffer, // input buffer
(DWORD) nInBufferSize, // size of the input buffer
NULL, // lpOutBuffer
0, // nOutBufferSize
(LPDWORD) lpBytesReturned, // number of bytes returned
(LPOVERLAPPED) lpOverlapped // OVERLAPPED structure
);
Through some analysis I found that while using this API the MBR of the disk is modified but the cluster bitmap of drive is not changed. I want to know the correct way of using this DeviceIO to expand a volume or some other API to do the same process.
need understand different between disk driver, which maintain info about disk layout and partitions (it size, offset from disk begin, style (gpt or mbr) ) and file system, which mount this partition.
IOCTL_DISK_GROW_PARTITION - this ioctl is handled by disk driver and extend partition, but this can not have effect for file system, which not handle this ioctl and have no knowledge at all that partition was extended. so you need additional ioctl use FSCTL_EXTEND_VOLUME - this ioctl already send and handle to file-system.
so if we have to do next steps
send IOCTL_DISK_GROW_PARTITION with
DISK_GROW_PARTITION as input buffer
send IOCTL_DISK_UPDATE_DRIVE_SIZE with DISK_GEOMETRY
as output buffer
send IOCTL_DISK_GET_PARTITION_INFO_EX with
PARTITION_INFORMATION_EX as output for get actual size of
partition now.
calculate new size of the volume, in sectors
LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart / dg.BytesPerSector;
(dg we got at step 2 and PartitionEntry at step 3)
finally use FSCTL_EXTEND_VOLUME
full code can be like next
int __cdecl SortPartitions(PPARTITION_INFORMATION_EX PartitionEntry1, PPARTITION_INFORMATION_EX PartitionEntry2)
{
if (!PartitionEntry1->PartitionNumber) return PartitionEntry2->PartitionNumber ? -1 : 0;
if (!PartitionEntry2->PartitionNumber) return +1;
if (PartitionEntry1->StartingOffset.QuadPart < PartitionEntry2->StartingOffset.QuadPart) return -1;
if (PartitionEntry1->StartingOffset.QuadPart > PartitionEntry2->StartingOffset.QuadPart) return +1;
return 0;
}
DWORD ExtendTest(HANDLE hDisk)
{
STORAGE_DEVICE_NUMBER sdn;
ULONG dwBytesRet;
if (!DeviceIoControl(hDisk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &sdn, sizeof(sdn), &dwBytesRet, NULL))
{
return GetLastError();
}
if (sdn.DeviceType != FILE_DEVICE_DISK || sdn.PartitionNumber != 0)
{
return ERROR_GEN_FAILURE;
}
GET_LENGTH_INFORMATION gli;
if (!DeviceIoControl(hDisk, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &gli, sizeof(gli), &dwBytesRet, NULL))
{
return GetLastError();
}
DbgPrint("Disk Length %I64x (%I64u)\n", gli.Length.QuadPart, gli.Length.QuadPart);
PVOID stack = alloca(guz);
union {
PVOID buf;
PDRIVE_LAYOUT_INFORMATION_EX pdli;
};
ULONG cb = 0, rcb, PartitionCount = 4;
for (;;)
{
if (cb < (rcb = FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry[PartitionCount])))
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, buf, cb, &dwBytesRet, NULL))
{
if (PartitionCount = pdli->PartitionCount)
{
PPARTITION_INFORMATION_EX PartitionEntry = pdli->PartitionEntry;
qsort(PartitionEntry, PartitionCount, sizeof(PARTITION_INFORMATION_EX),
(int (__cdecl *)(const void *, const void *))SortPartitions );
do
{
if (!PartitionEntry->PartitionNumber)
{
continue;
}
LARGE_INTEGER EndOffset;
LARGE_INTEGER MaximumOffset = PartitionCount != 1 ? (PartitionEntry + 1)->StartingOffset : gli.Length;
EndOffset.QuadPart = PartitionEntry->StartingOffset.QuadPart + PartitionEntry->PartitionLength.QuadPart;
if (EndOffset.QuadPart > MaximumOffset.QuadPart)
{
//??
__debugbreak();
}
else if (EndOffset.QuadPart < MaximumOffset.QuadPart)
{
DISK_GROW_PARTITION dgp;
dgp.PartitionNumber = PartitionEntry->PartitionNumber;
dgp.BytesToGrow.QuadPart = MaximumOffset.QuadPart - EndOffset.QuadPart;
WCHAR sz[128];
swprintf(sz, L"\\\\?\\GLOBALROOT\\Device\\Harddisk%d\\Partition%u", sdn.DeviceNumber, dgp.PartitionNumber);
HANDLE hPartition = CreateFile(sz, FILE_READ_ACCESS|FILE_WRITE_ACCESS, FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hPartition != INVALID_HANDLE_VALUE)
{
// +++ begin extend
BOOL fOk = FALSE;
DISK_GEOMETRY dg;
if (DeviceIoControl(hPartition, IOCTL_DISK_GROW_PARTITION, &dgp, sizeof(dgp), 0, 0, &dwBytesRet, 0) &&
DeviceIoControl(hPartition, IOCTL_DISK_UPDATE_DRIVE_SIZE, 0, 0, &dg, sizeof(dg), &dwBytesRet, 0) &&
DeviceIoControl(hPartition, IOCTL_DISK_GET_PARTITION_INFO_EX, 0, 0, PartitionEntry, sizeof(*PartitionEntry), &dwBytesRet, 0)
)
{
LONGLONG SectorsPerPartition = PartitionEntry->PartitionLength.QuadPart / dg.BytesPerSector;
fOk = DeviceIoControl(hPartition, FSCTL_EXTEND_VOLUME, &SectorsPerPartition,
sizeof(SectorsPerPartition), 0, 0, &dwBytesRet, 0);
}
if (!fOk)
{
GetLastError();
}
//--- end extend
CloseHandle(hPartition);
}
}
// else EndOffset.QuadPart == MaximumOffset.QuadPart - partition can not be extended
} while (PartitionEntry++, --PartitionCount);
}
return NOERROR;
}
switch (ULONG err = GetLastError())
{
case ERROR_MORE_DATA:
PartitionCount = pdli->PartitionCount;
continue;
case ERROR_BAD_LENGTH:
case ERROR_INSUFFICIENT_BUFFER:
PartitionCount <<= 1;
continue;
default:
return err;
}
}
}
DWORD ExtendTest()
{
HANDLE hDisk = CreateFileW(L"\\\\?\\PhysicalDrive0", FILE_GENERIC_READ|FILE_GENERIC_WRITE,
FILE_SHARE_VALID_FLAGS, 0, OPEN_EXISTING, 0, 0);
if (hDisk != INVALID_HANDLE_VALUE)
{
DWORD err = ExtendTest(hDisk);
CloseHandle(hDisk);
return err;
}
return GetLastError();
}

How to use deviceiocontrol function properly

This is my code:
Code:
HANDLE HandelUsb= CreateFile(L"\\\\.\\G:", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (HandelUsb == INVALID_HANDLE_VALUE)
{
printf("Terminal failure: Unable to open usb ERROR CODE:0x%x\n", GetLastError());
return 1;
}
DISK_GEOMETRY d = { 0 };
DWORD dwReturned = 0;
int gs =DeviceIoControl(HandelUsb, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &d, sizeof(DISK_GEOMETRY),&dwReturned, NULL);
printf("%d\n", gs);
if (d.MediaType == RemovableMedia)
{
DWORD dwReturned2 = 0;
MEDIA_SERIAL_NUMBER_DATA data={ 0 };
if (DeviceIoControl(HandelUsb, IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER, NULL, 0, &data,sizeof(MEDIA_SERIAL_NUMBER_DATA), &dwReturned2, NULL)) {
printf("SerialNumberLength %d\nResult %d\nReserved[2] %s\nSerialNumberData[1] %s ", data.SerialNumberLength, data.Result, data.Reserved, data.SerialNumberData);
}
else {
printf("faild to get serial number ERROR CODE:0x%x\n", GetLastError());
}
}
CloseHandle(HandelUsb);
return 0;
Everything works well except for the function
Code:
DeviceIoControl(HandelUsb, IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER, NULL, 0, &data,sizeof(MEDIA_SERIAL_NUMBER_DATA), &dwReturned2, NULL)
It always fails (returns a value of 0), GetLastError returns the value 0X1 (problem function).
Maybe someone here can show me what I'm missing here?
Following the comment of #IInspectable ,i changed the code to it:
//volume handle to device handle
VOLUME_DISK_EXTENTS volumeToDevice = { 0 };
DWORD Returned = 0;
DeviceIoControl(HandelToUsb,IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,NULL,0,&volumeToDevice,sizeof(VOLUME_DISK_EXTENTS),&Returned,NULL);
WCHAR volume[150] ;
swprintf_s(volume, L"\\\\.\\PhysicalDrive%d", volumeToDevice.Extents[0].DiskNumber);
wprintf(L"%s\n", volume);
//handle to phisicalDrive
HANDLE HandelUsb = CreateFile(volume, 0, FILE_SHARE_READ |FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
DWORD dwReturned2 = 0;
MEDIA_SERIAL_NUMBER_DATA data={ 0 };
if (DeviceIoControl(HandelUsb, IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER, NULL, 0, &data,sizeof(MEDIA_SERIAL_NUMBER_DATA), &dwReturned2, NULL)) {
printf("SerialNumberLength %d\nResult %d\nReserved[2] %s\nSerialNumberData[1] %s ", data.SerialNumberLength, data.Result, data.Reserved, data.SerialNumberData);
}
else {
printf("faild to get serial number ERROR CODE:0x%x\n", GetLastError());
}
I still get a failure 0X1 on function
DeviceIoControl (Handel Usb, IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER, NULL, 0, & data, sizeof (MEDIA_SERIAL_NUMBER_DATA), & dwReturned2, NULL)
I ran Windus 7
i tried to Change the permissions function CreateFile (Add GENERIC_EXECUTE , replace to GENERIC_ALL add FILE_ATTRIBUTE_NORMAL ), play with the parameters of the DeviceIoControl.

sendarp with multithreading function is not working for whole subnet (wifi environment)

I was trying to fetch Mac addrs of all the devices present in WiFi environment(whole subnet).
Initially when i ran the code approx it took 10 mins to get the result for whole subnet so in order to reduce the time i used multithreaded concept in windows machine but this method is not at all working.
I am pasting the code snippet below.
Even i tried different logic like running 255, 100, 50 ,2 threads at a time but still it failed.
I suspect synchronization issue in this but i don't have any idea to resolve this, so please help me in this getting done.
DWORD WINAPI GetMacAddrOfSubNet(LPVOID lpParam)
{
DWORD dwRetVal;
IPAddr DestIp = 0;
IPAddr SrcIp = 0; /* default for src ip */
ULONG MacAddr[2]; /* for 6-byte hardware addresses */
ULONG PhysAddrLen = 6; /* default to length of six bytes */
char look[100];
strcpy(look ,(char *)lpParam);
DestIp = inet_addr(look);
memset(&MacAddr, 0xff, sizeof (MacAddr));
/*Pinging particular ip and retrning mac addrs if response is thr*/
dwRetVal = SendARP(DestIp, SrcIp, &MacAddr, &PhysAddrLen);
if (dwRetVal == NO_ERROR)
{
/**/
}
return 0;
}
extern "C" __declspec(dllexport) int __cdecl PopulateARPTable(char *IpSubNetMask)
{
char ipn[100];
char buffer[10];
unsigned int k;
DWORD dwThreadIdArray[260];
HANDLE hThreadArray[260];
/*Run 255 threads at once*/
for (k=1; k<255; k++)
{
itoa(k, buffer, 10);
strcpy(ipn, IpSubNetMask);
strcat(ipn, ".");
strcat(ipn, buffer);
/*Thread creation */
hThreadArray[k] = CreateThread( NULL, 0, GetMacAddrOfSubNet, ipn, 0, &dwThreadIdArray[k]);
if (hThreadArray[k] == NULL)
{
//ExitProcess(3);
}
}
WaitForMultipleObjects(255, hThreadArray, TRUE, INFINITE);
return 0;
}
The ipn buffer only exists once. You are using and modifying it as parameter for your (up to) 255 threads. And you expect that the statement strcpy(look ,(char *)lpParam) in the thread will be performed before the main thread modifies ipnagain for calling the next thread. But this is not the case, at least it's not guaranteed. So your threads may use wrong parameters.
Either use different buffers for each thread, or implement a synchronization, that ensures that the parameter has been copied by the thread before main thread modifies the buffer again.
I've done this already for Excel, wrote a multi-threaded DLL that in addition to getting MAC addresses, will do DNS reverse hostname and ICMP ping RT.
Lemme know if you want the VBA code that goes with it. The source for the C-based DLL (which you may be happy with as a template) is:
/*
ExcelNet library: Provide threaded networking functions
NOTE: Serially doing these on the network involves serially waiting for timeouts, much ouchies!
Written by: Danny Holstein
*/
#if 1 // header stuff
#include <windows.h>
#include <iphlpapi.h>
#include <icmpapi.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define MSEXPORT __declspec(dllexport)
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#define BUFSZ 256
typedef struct {
char ip[BUFSZ]; // IP addresses in dotted notation.
int ipSize; // size of IP address buffer
char data[BUFSZ]; // general network data (MAC, hostname, etc)
int dataSize; // size of data buffer ^
int err_no; // WinAPI error number
int (*func)(LPCSTR Addr, char* buf, int BufSz); // function address, &GetNameInfos, &GetARP or &GetICMP
} NET_DATA;
int GetARP(LPCSTR Addr, char* Buf, int BufSz);
int GetNameInfos(LPCSTR Addr, char* Buf, int BufSz);
int GetICMP(LPCSTR Addr, char* Buf, int BufSz);
char msg_dbg[BUFSZ], dan[BUFSZ];
#define DEBUG_PRT() {snprintf(msg_dbg, BUFSZ, "lineno = %d\tfunc = %s", __LINE__ , __func__); MessageBox(0, msg_dbg, "debug", 0);}
#define DEBUG_MSG(msg) {snprintf(msg_dbg, BUFSZ, "msg=\"%s\"\tlineno = %d\tfunc = %s", msg, __LINE__ , __func__); MessageBox(0, msg_dbg, "debug", 0);}
#if 0 // documentation indicates malloc/realloc/free shouldn't be used in DLLs
#define malloc(A) malloc(A)
#define realloc(A, B) realloc(A, B)
#define free(A) free(A)
// #define NOMEMLEAK // dudint work
#else // kinda works, when NOT allocating all the NET_DATA structure elements
#define malloc(A) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, A)
#define realloc(A, B) HeapReAlloc(GetProcessHeap(), HEAP_GENERATE_EXCEPTIONS, A, B)
#define free(A) (void) HeapFree(A, HEAP_GENERATE_EXCEPTIONS, NULL)
#define NOMEMLEAK
#endif
#endif
MSEXPORT void __stdcall ArrayDGH(SAFEARRAY **IntArr, SAFEARRAY **StrArr)
{
SAFEARRAY *A = (SAFEARRAY*) (*IntArr);
SAFEARRAY *S = (SAFEARRAY*) (*StrArr);
int n = (*A).rgsabound[0].cElements;
snprintf(dan, BUFSZ, "a num elems = %d, str num elems = %d", n, (*S).rgsabound[0].cElements); DEBUG_MSG(dan);
// for (int i=0; i<n; i++) {snprintf(dan, BUFSZ, "elem[%d] = %d", i, ((int*) (*A).pvData)[i]); DEBUG_MSG(dan);}
OLECHAR* str[] = {L"Da",L"Fuk",L"Waz",L"Dat?",L"dot",L"dot"};
for (int i=0; i<n; i++) {SysReAllocString(&(((BSTR*) (*S).pvData)[i]), str[i]);}
}
DWORD dwMilliseconds = 10000;
MSEXPORT void __stdcall SetTIMO(DWORD Timo) {dwMilliseconds = Timo;}
MSEXPORT bool __stdcall ExcelSendARP(LPCSTR Addr, BSTR* MAC)
{
char buf[BUFSZ];
int err = GetARP(Addr, buf, BUFSZ);
*MAC = SysAllocStringByteLen(buf, strlen(buf)); // avoid WIDE to ANSI stuff
return !err;
}
MSEXPORT bool __stdcall ExcelICMPRT(LPCSTR Addr, BSTR* RoundTrip)
{
char buf[BUFSZ];
int err = GetICMP(Addr, buf, BUFSZ);
*RoundTrip = SysAllocStringByteLen(buf, strlen(buf)); // avoid WIDE to ANSI stuff
return !err;
}
MSEXPORT bool __stdcall ExcelGetNameInfo(LPCSTR Addr, BSTR* NameInfo)
{
char buf[BUFSZ];
#ifdef TEST_FUNC_PTR
int (*FunAddr[2])(LPCSTR Addr, char** buf, int BufSz);
FunAddr[0] = &GetARP; FunAddr[1] = &GetNameInfos; // DRY code hooks
int err = (*(FunAddr[1]))(Addr, buf, BUFSZ);
#else
int err = GetNameInfos(Addr, buf, BUFSZ);
#endif
*NameInfo = SysAllocStringByteLen(buf, strlen(buf)); // avoid WIDE to ANSI stuff
return !err;
}
int GetNameInfos(LPCSTR Addr, char* buf, int BufSz)
{
ULONG inet; DWORD resp = 0; HOSTENT *tHI;
struct in_addr addr = { 0 };
if ((inet = inet_addr(Addr)) == INADDR_NONE) {
if (strcpy_s(buf, BufSz, "inet_addr failed and returned INADDR_NONE")) DEBUG_MSG("strcpy_s error!");
return inet;
}
addr.s_addr = inet; tHI = gethostbyaddr((char *) &addr, 4, AF_INET);
if (tHI == NULL) { // no reponse for this IP condition, decode condition and place in PCHAR buf
resp = WSAGetLastError();
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
return resp;
}
_snprintf_s(buf, BufSz-1, _TRUNCATE, "%s", tHI->h_name); // place hostname in PCHAR buf
return resp; // <- resp = 0, we have a hostname associated with this IP, SUCCESS!
}
int GetARP(LPCSTR Addr, char* buf, int BufSz)
{
#define BUFLEN 6
ULONG pMacAddr[BUFLEN], inet, BufLen = BUFLEN; DWORD resp = 0;
if ((inet = inet_addr(Addr)) == INADDR_NONE) {
if (strcpy_s(buf, BufSz, "inet_addr failed and returned INADDR_NONE")) DEBUG_MSG("strcpy_s error!");
return inet;
}
resp = SendARP(inet, 0, pMacAddr, &BufLen);
if (resp) { // no reponse for this IP condition, decode condition and place in PCHAR buf
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
return resp;
}
UCHAR *pMacAddrBytes = (UCHAR *) pMacAddr;
_snprintf_s(buf, BufSz, _TRUNCATE, "%02x:%02x:%02x:%02x:%02x:%02x", pMacAddrBytes[0], pMacAddrBytes[1], pMacAddrBytes[2],
pMacAddrBytes[3], pMacAddrBytes[4], pMacAddrBytes[5]); // place MAC in PCHAR buf
return resp; // <- resp = 0, we have a MAC associated with this IP, SUCCESS!
}
int GetICMP(LPCSTR Addr, char* buf, int BufSz)
{
HANDLE hIcmpFile;
ULONG inet; DWORD resp = 0;
char SendData[] = "Data Buffer";
LPVOID ReplyBuffer = NULL;
DWORD ReplySize = 0;
if ((inet = inet_addr(Addr)) == INADDR_NONE) {
if (strcpy_s(buf, BufSz, "inet_addr failed and returned INADDR_NONE")) DEBUG_MSG("strcpy_s error!");
return inet;
}
hIcmpFile = IcmpCreateFile();
if (hIcmpFile == INVALID_HANDLE_VALUE) {
resp = GetLastError();
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
return resp;
}
// Allocate space for at a single reply
ReplySize = sizeof (ICMP_ECHO_REPLY) + sizeof (SendData) + 8;
ReplyBuffer = (VOID *) malloc(ReplySize);
resp = IcmpSendEcho2(hIcmpFile, NULL, NULL, NULL,
inet, SendData, sizeof (SendData), NULL,
ReplyBuffer, ReplySize, dwMilliseconds);
PICMP_ECHO_REPLY pEchoReply = (PICMP_ECHO_REPLY) ReplyBuffer;
if (resp == 0) { // no reponse for this IP condition, decode condition and place in PCHAR buf
resp = pEchoReply->Status; // WSAGetLastError();
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, resp, 0, buf, BufSz, 0);
return resp;
}
_snprintf_s(buf, BufSz-1, _TRUNCATE, "%d", ((PICMP_ECHO_REPLY) ReplyBuffer)->RoundTripTime); // place roundtrip time in PCHAR buf (ASCII representation)
IcmpCloseHandle(hIcmpFile);
return 0; // we have a RT time in milliseconds associated with this IP, SUCCESS!
}
NET_DATA *NetData;
DWORD WINAPI tGetDATA(LPVOID NetData)
{
char buf[BUFSZ];
NET_DATA *m = NetData; // stupid me, I had allocated the space, instead of address of, not thinking it all disappears on exit
m->err_no = (*(m->func))(m->ip, buf, BUFSZ); // GetARP, GetNameInfos or GetICMP
if (_snprintf_s(m->data, m->dataSize-1, _TRUNCATE, "%s", buf) == -1) DEBUG_MSG("_snprintf_s error!");
// A resources error may have hit AFTER the calling function has returned, including having the thread/memory deallocated in the calling function
return 0;
}
MSEXPORT BSTR __stdcall ExcelRngNetData(UCHAR *list, ULONG *ErrNos, BSTR *DataArry, DWORD dwMilliseconds, char sep, char FunctType)
{ // take list of IP addresses (newline-separated), create thread for each to get network data. Return results in (sep-separated) BSTR.
int i=0, j, NumIPs=0, k = strlen(list), l=0;
#define NMSZ 100
char nm[NMSZ];
void* FuncAddr[3]; // DRY code hooks
FuncAddr[0] = &GetARP; FuncAddr[1] = &GetNameInfos; FuncAddr[2] = &GetICMP;
while (i<k && sscanf_s(list+i, "%[^\n]\n", nm, NMSZ)){i += strnlen_s(nm, NMSZ) + 1; NumIPs++;} // count newline-separated items before doing malloc(), because realloc() is REALLY resource intensive
NetData = malloc(NumIPs * sizeof(NET_DATA)); i = 0;
while (i<k && sscanf_s(list+i, "%[^\n]\n", nm, NMSZ)){ // load calling routines list into structures
j = strnlen_s(nm, NMSZ) + 1; i += j;
NetData[l].err_no = WAIT_TIMEOUT; // easy way to preset the error to a TIMEOUT, if the thread successfully completes before the timeout, this will be set to reflect its timeout
NetData[l].dataSize = BUFSZ;
NetData[l].func = FuncAddr[FunctType]; // DRY (Don't Repeat Yourself) code hook
if (strncpy_s(NetData[l].ip, (NetData[l].ipSize = BUFSZ), nm, j)) DEBUG_MSG("strcpy_s error!");
l++;
}
HANDLE *tHandles = malloc(NumIPs * sizeof(HANDLE)); DWORD ThreadId;
for (i=0; i<NumIPs; i++){
tHandles[i] = CreateThread(NULL, 0, tGetDATA, &(NetData[i]), 0, &ThreadId);
if (tHandles[i] == NULL) {DEBUG_MSG("Could not create threads!\nExiting now"); ExitProcess(3);}
}
if(WaitForMultipleObjects(NumIPs, tHandles, TRUE, dwMilliseconds) == WAIT_FAILED) {
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, GetLastError(), 0, dan, BUFSZ, 0); DEBUG_MSG(dan);
// Prolly means too many threads, kicked in when I exceeded 64; ERROR_INVALID_PARAMETER = "The parameter is incorrect"
}
#define CHUNK 1024
#define DATASZ 256 // tested with intentionally small size to check "safe" string functions
wchar_t wcs[DATASZ]; char MacChunk[DATASZ];
char *ans = malloc(CHUNK); int anslen = 0, anssz = CHUNK;
char separator[2]; separator[0] = sep; separator[1] = 0;
for(i=0; i<NumIPs; i++) { // build return BSTR and load array with data
CloseHandle(tHandles[i]); ErrNos[i] = NetData[i].err_no;
if (strncpy_s(MacChunk, DATASZ-1, NetData[i].err_no == 0 ? NetData[i].data : "", NetData[i].dataSize-1)) DEBUG_MSG("strcpy_s error!");
if (i<NumIPs-1 && sep != 0) if (strncat_s(MacChunk, DATASZ-1, separator, 1)) DEBUG_MSG("strcpy_s error!");
while (strnlen_s(MacChunk, DATASZ) > anssz - anslen -1) ans = realloc(ans, (anssz += CHUNK)); // choose CHUNK size to avoid constant realloc(), because realloc() is REALLY resource intensive
if (strncpy_s(&(ans[anslen]), DATASZ-1, MacChunk, DATASZ-1)) DEBUG_MSG("strcpy_s error!"); anslen += strnlen_s(MacChunk, DATASZ); // return data in returned BSTR
MultiByteToWideChar(CP_UTF8, 0,
ErrNos[i] == WAIT_TIMEOUT ? "The wait operation timed out." : NetData[i].data,
-1, wcs, DATASZ-1); // return data in supplied array
SysReAllocString(&DataArry[i], wcs);
}
BSTR r = SysAllocStringByteLen(ans, strlen(ans));
#ifdef NOMEMLEAK
free(NetData); free(tHandles); free(ans);
#endif
return r;
}

Resources