Discussion:
[Synce-devel] Librapi stuff
Mark Ellis
2007-12-11 10:01:38 UTC
Permalink
Hi Mark,
i was wondering whether you managed to find some time to look at the rapi
version1 stuff. I was looking at some old webpages from synce, regarding the
http://synce.sourceforge.net/synce/packet.php
Had a bit of a tinker, but not much yet. I quickly tried again to use
your new code with the rapi1 rapi_context_call, but no luck.
There I do see exactly the same stuff that I discovered myself while working
on the rapi2 stuff. What strikes me as odd in registry.c for example is lines
rapi_buffer_write_uint32 (context->send_buffer, hKey);
rapi_buffer_write_optional (context->send_buffer, lpClass, lpcbClass ?
*lpcbClass * sizeof(WCHAR) : 0, false);
rapi_buffer_write_optional_uint32(context->send_buffer, lpcbClass, true);
rapi_buffer_write_optional_uint32(context->send_buffer, lpReserved, false);
rapi_buffer_write_optional_uint32(context->send_buffer, lpcSubKeys, false);
rapi_buffer_write_optional_uint32(context->send_buffer, lpcbMaxSubKeyLen,
false);
rapi_buffer_write_optional_uint32(context->send_buffer, lpcbMaxClassLen,
false);
rapi_buffer_write_optional_uint32(context->send_buffer, lpcValues, false);
rapi_buffer_write_optional_uint32(context->send_buffer, lpcbMaxValueNameLen,
false);
rapi_buffer_write_optional_uint32(context->send_buffer, lpcbMaxValueLen,
false);
rapi_buffer_write_optional_uint32(context->send_buffer,
lpcbSecurityDescriptor, false);
rapi_buffer_write_optional (context->send_buffer, lpftLastWriteTime,
sizeof(FILETIME), false);
This means for example that when you are querying for all information of a
given regkey, you not only send the size of the buffer on the computer side
to hold the class name, but you also send the complete buffer over the wire.
This really looks dumb to me for a protocol, since the device does not need
to know about the buffer I have, except for how much info at max at may send
to me :)
Besides that, pretty much all of the other lines in the above code, deal with
info we should get from the device, so the amount of subkeys, the amount of
values, etc. Therefore, it is also not logical to send that over the line.
What you're saying makes perfect sense to me. Unfortunately we have no
way of knowing if the guy who thought this up had any sense at all :)
So far, from what I have seen on that website, which really does with rapi1
calls, since the command code for CeGetSpecialFolderPath is only 0x44 in the
rapi1, not in the rapi2, the stuff that needs to be sent over the line is
actually the same. So did you already try to put the exact code, except for
the command part in the registry.c ?
Really would like to get to the point that the registry tool can be updated
also. If that works we can look at some of the other functions that are not
implemented yet.
Me too. I'm going to, hopefully today, go through all the rapi1 registry
calls and see exactly what works.

Ta
Mark
Mark Ellis
2007-12-11 17:28:40 UTC
Permalink
Post by Mark Ellis
Me too. I'm going to, hopefully today, go through all the rapi1 registry
calls and see exactly what works.
I was thinking, you could see if the problem lays only in the InfoKey, or
also in the EnumValue. The only reason I call the InfoKey is that I want
to know what sizes for the buffers I need to reserve.
I'm getting there, InfoKey now works. There were a few problems, but the
killer was the implementation trying to GetLastError, which isn't
provided by this function, who knows why. This of course meant the
buffer position was 4 bytes too far in.

Unfortunately, EnumValue still doesn't work.
What you could try is apply my patches to the synce-registry program, but
instead of calling the InfoKey function to determine these values, you can
set them manually
//First determine the size of the holding arrays for all
//subvalues/keys
DWORD lpcSubKeys ;
DWORD lpcbMaxSubKeyLen ;
DWORD lpcbMaxClassLen ;
DWORD lpcValues ;
DWORD lpcbMaxValueNameLen ;
DWORD lpcbMaxValueLen ;
lpcbMaxClassLen++ ;
lpcbMaxValueNameLen++ ;
lpcbMaxValueLen++ ;
lpcbMaxSubKeyLen++ ;
The MaxClassLen you can set to 256 (that is 255 chars + the \0 terminator)
The MaxSubKeyLen you can set to the max path len: MAX_PATH
the other two values can be quite high, I am not sure whether a limit is
put on the value len or the valuenamelen, but the maximum value len I
encountered is 4096 bytes. If you just put it for testing at something
like 16384 it should be ok.
Then we will at least know whether the problem is within QueryInfo or
within EnumValue.
The answer seems to be both.

We can hardcode sizes if it comes to it, but now I've done InfoKey I
think I've got the hang of it. It'll need to be fixed sometime anyway,
might as well do it right.

David, after my first experience of reverse engineering in rapi, I'm
humbled by the effort it must have taken to get librapi to the point
it's at, hats off to you.

Mark
Guido Diepen
2007-12-11 19:09:50 UTC
Permalink
Post by Mark Ellis
Post by Mark Ellis
Me too. I'm going to, hopefully today, go through all the rapi1
registry calls and see exactly what works.
I was thinking, you could see if the problem lays only in the InfoKey, or
also in the EnumValue. The only reason I call the InfoKey is that I want
to know what sizes for the buffers I need to reserve.
I'm getting there, InfoKey now works. There were a few problems, but the
killer was the implementation trying to GetLastError, which isn't
provided by this function, who knows why. This of course meant the
buffer position was 4 bytes too far in.
Unfortunately, EnumValue still doesn't work.
What you could try is apply my patches to the synce-registry program, but
instead of calling the InfoKey function to determine these values, you
can set them manually
//First determine the size of the holding arrays for all
//subvalues/keys
DWORD lpcSubKeys ;
DWORD lpcbMaxSubKeyLen ;
DWORD lpcbMaxClassLen ;
DWORD lpcValues ;
DWORD lpcbMaxValueNameLen ;
DWORD lpcbMaxValueLen ;
lpcbMaxClassLen++ ;
lpcbMaxValueNameLen++ ;
lpcbMaxValueLen++ ;
lpcbMaxSubKeyLen++ ;
The MaxClassLen you can set to 256 (that is 255 chars + the \0
terminator) The MaxSubKeyLen you can set to the max path len: MAX_PATH
the other two values can be quite high, I am not sure whether a limit is
put on the value len or the valuenamelen, but the maximum value len I
encountered is 4096 bytes. If you just put it for testing at something
like 16384 it should be ok.
Then we will at least know whether the problem is within QueryInfo or
within EnumValue.
The answer seems to be both.
We can hardcode sizes if it comes to it, but now I've done InfoKey I
think I've got the hang of it. It'll need to be fixed sometime anyway,
might as well do it right.
Yup, that was my idea also... I saw that there were some more NULL references,
so maybe I will implement the other functions also :)
Post by Mark Ellis
David, after my first experience of reverse engineering in rapi, I'm
humbled by the effort it must have taken to get librapi to the point
it's at, hats off to you.
Make that another hat here that is taken off !!! :)

Guido
--
Aviation is proof that given the will, we have the
capacity to achieve the impossible.
--Eddie Rickenbacker
David Eriksson
2007-12-11 20:02:07 UTC
Permalink
Post by Mark Ellis
Post by Mark Ellis
Me too. I'm going to, hopefully today, go through all the rapi1 registry
calls and see exactly what works.
I was thinking, you could see if the problem lays only in the InfoKey, or
also in the EnumValue. The only reason I call the InfoKey is that I want
to know what sizes for the buffers I need to reserve.
I'm getting there, InfoKey now works. There were a few problems, but the
killer was the implementation trying to GetLastError, which isn't
provided by this function, who knows why. This of course meant the
buffer position was 4 bytes too far in.
Unfortunately, EnumValue still doesn't work.
I think that the correct solution is to not read the reserved value,
i.e. removing this line from both functions:

rapi_buffer_read_optional_uint32(context->recv_buffer, lpReserved);

Otherwise, they should be implemented just fine. Here are my specs. "No
data" means that the value should not be sent. "Data" means that the
value should be sent. (Controls parameter to rapi_buffer_write_optional*
functions.)


RegQueryInfoKey:

Request

4 bytes HKEY hKey
*lpcbClass bytes optional LPWSTR lpClass
4 bytes optional data LPDWORD lpcbClass,
4 bytes optional no data LPDWORD lpReserved,
4 bytes optional no data LPDWORD lpcSubKeys,
4 bytes optional no data LPDWORD lpcbMaxSubKeyLen,
4 bytes optional no data LPDWORD lpcbMaxClassLen,
4 bytes optional no data LPDWORD lpcValues,
4 bytes optional no data LPDWORD lpcbMaxValueNameLen,
4 bytes optional no data LPDWORD lpcbMaxValueLen,
4 bytes optional no data LPDWORD lpcbSecurityDescriptor,
8 bytes optional no data PFILETIME lpftLastWriteTime

Response

*lpcbClass bytes optional LPWSTR lpClass
4 bytes optional data LPDWORD lpcbClass,
ignoring LPDWORD lpReserved,
4 bytes optional LPDWORD lpcSubKeys,
4 bytes optional LPDWORD lpcbMaxSubKeyLen,
4 bytes optional LPDWORD lpcbMaxClassLen,
4 bytes optional LPDWORD lpcValues,
4 bytes optional LPDWORD lpcbMaxValueNameLen,
4 bytes optional LPDWORD lpcbMaxValueLen,
4 bytes optional LPDWORD lpcbSecurityDescriptor,
8 bytes optional PFILETIME lpftLastWriteTime


RegEnumValue

4 bytes HKEY hKey,
4 bytes DWORD dwIndex,
*lpcbValueName bytes optional no data LPWSTR lpszValueName,
4 bytes optional data LPDWORD lpcbValueName,
4 bytes optional no data LPDWORD lpReserved,
4 bytes optional no data LPDWORD lpType,
*lpcbData bytes optional no data LPBYTE lpData,
4 bytes optional data LPDWORD lpcbData

Response

4 bytes last error
4 bytes return value
*lpcbValueName bytes optional LPWSTR lpszValueName,
4 bytes optional LPDWORD lpcbValueName,
ignoring LPDWORD lpReserved,
4 bytes optional LPDWORD lpType,
*lpcbData bytes optional LPBYTE lpData,
4 bytes optional LPDWORD lpcbData
Post by Mark Ellis
What you could try is apply my patches to the synce-registry program, but
instead of calling the InfoKey function to determine these values, you can
set them manually
//First determine the size of the holding arrays for all
//subvalues/keys
DWORD lpcSubKeys ;
DWORD lpcbMaxSubKeyLen ;
DWORD lpcbMaxClassLen ;
DWORD lpcValues ;
DWORD lpcbMaxValueNameLen ;
DWORD lpcbMaxValueLen ;
lpcbMaxClassLen++ ;
lpcbMaxValueNameLen++ ;
lpcbMaxValueLen++ ;
lpcbMaxSubKeyLen++ ;
The MaxClassLen you can set to 256 (that is 255 chars + the \0 terminator)
The MaxSubKeyLen you can set to the max path len: MAX_PATH
the other two values can be quite high, I am not sure whether a limit is
put on the value len or the valuenamelen, but the maximum value len I
encountered is 4096 bytes. If you just put it for testing at something
like 16384 it should be ok.
Then we will at least know whether the problem is within QueryInfo or
within EnumValue.
The answer seems to be both.
We can hardcode sizes if it comes to it, but now I've done InfoKey I
think I've got the hang of it. It'll need to be fixed sometime anyway,
might as well do it right.
David, after my first experience of reverse engineering in rapi, I'm
humbled by the effort it must have taken to get librapi to the point
it's at, hats off to you.
Hey, the reverse engineering is the fun part! :-)


Cheers,

David
--
Guido Diepen
2007-12-11 20:55:07 UTC
Permalink
Post by David Eriksson
I think that the correct solution is to not read the reserved value,
Within the rapi2 stuff I already removed that, figured that it would only be
something to be used within the CeReg.. functions, not actually something
with the device.
Post by David Eriksson
rapi_buffer_read_optional_uint32(context->recv_buffer, lpReserved);
Otherwise, they should be implemented just fine. Here are my specs. "No
data" means that the value should not be sent. "Data" means that the
value should be sent. (Controls parameter to rapi_buffer_write_optional*
functions.)
I guess that this part changed then in the rapi2 stuff, because when using the
rapi_buffer_read_optional_uint32, this went wrong. I don't know what exactly
the optional means in these names, but it looks to me that the device sends a
0/1 bit denoting whether a certain value is sent. (If i understand the
readd_optional_ code correctly). Within the rapi2 this did NOT work, because
for example with the RegQueryInfo function it can be seen that all values are
sent, no preceding 1 values. So if I would use the option_read_uint32 there,
this would not work, it would try to read too much.

Furthermore, regarding the strings and blocks of data, you just tell to the
device how much you will expect in the response from the device. This value
must always be >= 1, since you will always get at least 1 dword backup from
the device denoting the size of the buffer that follows. If you did not want
any info from the device, this value will be 0, but the value 0 (the length)
you must read :)

Finally, I guess that there was a small error in the read_string method,
because the device does not send the terminating \0 character. The example
that I found on the old-website
(http://synce.sourceforge.net/synce/packet.php) shows a rapi1 call where we
want to find out the Special folder path.
It states the length is 0x0d. this corresponds exactly to the length of:
"\My Documents"

It shows a null terminator after this string, but in all the tests I have done
with RegEnumValue, this 0 terminator does not exist and the next dword
belongs to the next parameter. I am not sure whether this also holds for the
rapi1 though, but for sure it holds for the rapi2 stuff.

If i am correct, this already has been taken care of with the patch I supplied
earlier to mark ellis.
Post by David Eriksson
Request
4 bytes HKEY hKey
*lpcbClass bytes optional LPWSTR lpClass
4 bytes optional data LPDWORD lpcbClass,
4 bytes optional no data LPDWORD lpReserved,
4 bytes optional no data LPDWORD lpcSubKeys,
4 bytes optional no data LPDWORD lpcbMaxSubKeyLen,
4 bytes optional no data LPDWORD lpcbMaxClassLen,
4 bytes optional no data LPDWORD lpcValues,
4 bytes optional no data LPDWORD lpcbMaxValueNameLen,
4 bytes optional no data LPDWORD lpcbMaxValueLen,
4 bytes optional no data LPDWORD lpcbSecurityDescriptor,
8 bytes optional no data PFILETIME lpftLastWriteTime
Response
*lpcbClass bytes optional LPWSTR lpClass
4 bytes optional data LPDWORD lpcbClass,
ignoring LPDWORD lpReserved,
4 bytes optional LPDWORD lpcSubKeys,
4 bytes optional LPDWORD lpcbMaxSubKeyLen,
4 bytes optional LPDWORD lpcbMaxClassLen,
4 bytes optional LPDWORD lpcValues,
4 bytes optional LPDWORD lpcbMaxValueNameLen,
4 bytes optional LPDWORD lpcbMaxValueLen,
4 bytes optional LPDWORD lpcbSecurityDescriptor,
8 bytes optional PFILETIME lpftLastWriteTime
I don't understand what you mean with the optional here, since the device must
always send this information because it does not have any knowledge of what
the user requested (that is not sent by us in the request)
Post by David Eriksson
Hey, the reverse engineering is the fun part! :-)
I have to agree that it is the fun part. Unfortunately I don't have the
possibility of booting into windows and get the data. It is really fun to see
that without actually knowing anything, you start to make educated guesses
about what would be useful and what not and it is soooo nice if your guesses
turn out to be right :)

As mentioned, I saw that there still some gaps to be filled in with the rapi2
API, I will see what I can do during the week for those. Unfortunately these
are the more 'dangerous ones', like delete keys, delete values, etc :)
Note to self: Make backup :)

Regards,

Guido Diepen
--
Aviation is proof that given the will, we have the
capacity to achieve the impossible.
--Eddie Rickenbacker
Mark Ellis
2007-12-12 08:20:28 UTC
Permalink
Post by David Eriksson
Post by Mark Ellis
Post by Mark Ellis
Me too. I'm going to, hopefully today, go through all the rapi1 registry
calls and see exactly what works.
I was thinking, you could see if the problem lays only in the InfoKey, or
also in the EnumValue. The only reason I call the InfoKey is that I want
to know what sizes for the buffers I need to reserve.
I'm getting there, InfoKey now works. There were a few problems, but the
killer was the implementation trying to GetLastError, which isn't
provided by this function, who knows why. This of course meant the
buffer position was 4 bytes too far in.
Unfortunately, EnumValue still doesn't work.
I think that the correct solution is to not read the reserved value,
Seems to be working ok with this still in, but I have actually supplied
a non-NULL location in my testing, hope it doesn't break later.
Post by David Eriksson
rapi_buffer_read_optional_uint32(context->recv_buffer, lpReserved);
Otherwise, they should be implemented just fine. Here are my specs. "No
data" means that the value should not be sent. "Data" means that the
value should be sent. (Controls parameter to rapi_buffer_write_optional*
functions.)
Request
4 bytes HKEY hKey
*lpcbClass bytes optional LPWSTR lpClass
4 bytes optional data LPDWORD lpcbClass,
4 bytes optional no data LPDWORD lpReserved,
4 bytes optional no data LPDWORD lpcSubKeys,
4 bytes optional no data LPDWORD lpcbMaxSubKeyLen,
4 bytes optional no data LPDWORD lpcbMaxClassLen,
4 bytes optional no data LPDWORD lpcValues,
4 bytes optional no data LPDWORD lpcbMaxValueNameLen,
4 bytes optional no data LPDWORD lpcbMaxValueLen,
4 bytes optional no data LPDWORD lpcbSecurityDescriptor,
8 bytes optional no data PFILETIME lpftLastWriteTime
This was all fine.
Post by David Eriksson
Response
*lpcbClass bytes optional LPWSTR lpClass
4 bytes optional data LPDWORD lpcbClass,
ignoring LPDWORD lpReserved,
4 bytes optional LPDWORD lpcSubKeys,
4 bytes optional LPDWORD lpcbMaxSubKeyLen,
4 bytes optional LPDWORD lpcbMaxClassLen,
4 bytes optional LPDWORD lpcValues,
4 bytes optional LPDWORD lpcbMaxValueNameLen,
4 bytes optional LPDWORD lpcbMaxValueLen,
4 bytes optional LPDWORD lpcbSecurityDescriptor,
8 bytes optional PFILETIME lpftLastWriteTime
Had to take out the aforementioned read of last_error. Also had to swap
lpClass and lpcbClass, ie read the size first, perfectly logical but
breaks the parameter passing order, bizarre. Do you think when M$
assigns these things for someone to spec, it explicitly states "make it
as awkward as possible".
Post by David Eriksson
RegEnumValue
4 bytes HKEY hKey,
4 bytes DWORD dwIndex,
*lpcbValueName bytes optional no data LPWSTR lpszValueName,
4 bytes optional data LPDWORD lpcbValueName,
4 bytes optional no data LPDWORD lpReserved,
4 bytes optional no data LPDWORD lpType,
*lpcbData bytes optional no data LPBYTE lpData,
4 bytes optional data LPDWORD lpcbData
Response
4 bytes last error
4 bytes return value
*lpcbValueName bytes optional LPWSTR lpszValueName,
4 bytes optional LPDWORD lpcbValueName,
ignoring LPDWORD lpReserved,
4 bytes optional LPDWORD lpType,
*lpcbData bytes optional LPBYTE lpData,
4 bytes optional LPDWORD lpcbData
Had to remove the last_error read again, still testing.
Post by David Eriksson
Post by Mark Ellis
David, after my first experience of reverse engineering in rapi, I'm
humbled by the effort it must have taken to get librapi to the point
it's at, hats off to you.
Hey, the reverse engineering is the fun part! :-)
Analyzing the returns can be quite fun, randomly guessing what to send
can become slightly more frustrating :)

Mark
Mark Ellis
2007-12-12 09:53:40 UTC
Permalink
Post by Mark Ellis
Post by David Eriksson
Post by Mark Ellis
I'm getting there, InfoKey now works. There were a few problems, but the
killer was the implementation trying to GetLastError, which isn't
provided by this function, who knows why. This of course meant the
buffer position was 4 bytes too far in.
Unfortunately, EnumValue still doesn't work.
I think that the correct solution is to not read the reserved value,
Seems to be working ok with this still in, but I have actually supplied
a non-NULL location in my testing, hope it doesn't break later.
Post by David Eriksson
rapi_buffer_read_optional_uint32(context->recv_buffer, lpReserved);
Otherwise, they should be implemented just fine. Here are my specs. "No
data" means that the value should not be sent. "Data" means that the
value should be sent. (Controls parameter to rapi_buffer_write_optional*
functions.)
Request
4 bytes HKEY hKey
*lpcbClass bytes optional LPWSTR lpClass
4 bytes optional data LPDWORD lpcbClass,
4 bytes optional no data LPDWORD lpReserved,
4 bytes optional no data LPDWORD lpcSubKeys,
4 bytes optional no data LPDWORD lpcbMaxSubKeyLen,
4 bytes optional no data LPDWORD lpcbMaxClassLen,
4 bytes optional no data LPDWORD lpcValues,
4 bytes optional no data LPDWORD lpcbMaxValueNameLen,
4 bytes optional no data LPDWORD lpcbMaxValueLen,
4 bytes optional no data LPDWORD lpcbSecurityDescriptor,
8 bytes optional no data PFILETIME lpftLastWriteTime
This was all fine.
Post by David Eriksson
Response
*lpcbClass bytes optional LPWSTR lpClass
4 bytes optional data LPDWORD lpcbClass,
ignoring LPDWORD lpReserved,
4 bytes optional LPDWORD lpcSubKeys,
4 bytes optional LPDWORD lpcbMaxSubKeyLen,
4 bytes optional LPDWORD lpcbMaxClassLen,
4 bytes optional LPDWORD lpcValues,
4 bytes optional LPDWORD lpcbMaxValueNameLen,
4 bytes optional LPDWORD lpcbMaxValueLen,
4 bytes optional LPDWORD lpcbSecurityDescriptor,
8 bytes optional PFILETIME lpftLastWriteTime
Had to take out the aforementioned read of last_error. Also had to swap
lpClass and lpcbClass, ie read the size first, perfectly logical but
breaks the parameter passing order, bizarre. Do you think when M$
assigns these things for someone to spec, it explicitly states "make it
as awkward as possible".
Post by David Eriksson
RegEnumValue
4 bytes HKEY hKey,
4 bytes DWORD dwIndex,
*lpcbValueName bytes optional no data LPWSTR lpszValueName,
4 bytes optional data LPDWORD lpcbValueName,
4 bytes optional no data LPDWORD lpReserved,
4 bytes optional no data LPDWORD lpType,
*lpcbData bytes optional no data LPBYTE lpData,
4 bytes optional data LPDWORD lpcbData
Response
4 bytes last error
4 bytes return value
*lpcbValueName bytes optional LPWSTR lpszValueName,
4 bytes optional LPDWORD lpcbValueName,
ignoring LPDWORD lpReserved,
4 bytes optional LPDWORD lpType,
*lpcbData bytes optional LPBYTE lpData,
4 bytes optional LPDWORD lpcbData
Had to remove the last_error read again, still testing.
Time to contradict myself.

I said that last error wasn't returned by these functions. Well it does
seem to always be zero, but I need to read it because the return value
is definitely second in the buffer. This becomes obvious when stuck in
an infinite loop when you're certain you're checking for
ERROR_NO_MORE_ITEMS :)

I'm still a uint32 short in the buffer, so what seems most likely is
that the device does not return, in the case of enumvalue, the size of
the name string, we're left to figure that out. Same applies to infokey
with regard to the class name.

Anyone see any glaring errors in my reasoning ?

Mark
David Eriksson
2007-12-12 12:44:57 UTC
Permalink
Post by Mark Ellis
Time to contradict myself.
I said that last error wasn't returned by these functions. Well it does
seem to always be zero, but I need to read it because the return value
is definitely second in the buffer. This becomes obvious when stuck in
an infinite loop when you're certain you're checking for
Post by Mark Ellis
ERROR_NO_MORE_ITEMS :)
I'm still a uint32 short in the buffer, so what seems most likely is
that the device does not return, in the case of enumvalue, the size of
the name string, we're left to figure that out. Same applies to infokey
with regard to the class name.
Post by Mark Ellis
Anyone see any glaring errors in my reasoning ?
Is that with or without the following line enabled? Because it will eat at
least four bytes and I'm quite certain that it should not be there:

rapi_buffer_read_optional_uint32(context->recv_buffer, lpReserved);


Regards,

\David
Mark Ellis
2007-12-13 08:32:35 UTC
Permalink
Post by Mark Ellis
Post by Mark Ellis
Time to contradict myself.
I said that last error wasn't returned by these functions. Well it does
seem to always be zero, but I need to read it because the return value
is definitely second in the buffer. This becomes obvious when stuck in
an infinite loop when you're certain you're checking for
Post by Mark Ellis
ERROR_NO_MORE_ITEMS :)
I'm still a uint32 short in the buffer, so what seems most likely is
that the device does not return, in the case of enumvalue, the size of
the name string, we're left to figure that out. Same applies to infokey
with regard to the class name.
Post by Mark Ellis
Anyone see any glaring errors in my reasoning ?
Is that with or without the following line enabled? Because it will eat at
rapi_buffer_read_optional_uint32(context->recv_buffer, lpReserved);
Regards,
\David
I've disabled that line, it did indeed seem to be the problem. I've done
the same thing in enumvalue, definitely helps, don't seem to be quite
there yet.

Mark
Guido Diepen
2007-12-13 08:49:36 UTC
Permalink
Hi mark,
Post by Mark Ellis
I've disabled that line, it did indeed seem to be the problem. I've done
the same thing in enumvalue, definitely helps, don't seem to be quite
there yet.
If you would provide me with the buffer dumps of both the receiving and
sending buffers, I might be able to help out a bit. Plus a text denoting what
parameters you are trying to send and receive.

Guido Diepen
--
Aviation is proof that given the will, we have the
capacity to achieve the impossible.
--Eddie Rickenbacker
Mark Ellis
2007-12-13 18:19:26 UTC
Permalink
Post by Guido Diepen
Hi mark,
Post by Mark Ellis
I've disabled that line, it did indeed seem to be the problem. I've done
the same thing in enumvalue, definitely helps, don't seem to be quite
there yet.
If you would provide me with the buffer dumps of both the receiving and
sending buffers, I might be able to help out a bit. Plus a text denoting what
parameters you are trying to send and receive.
Guido Diepen
Guido, I think I've cracked it, turned out to be an unsuccessful
modification that I hadn't reverted, typical.

I'm going to double check what I have, and will hopefully commit
everything later today.

Mark
Mark Ellis
2007-12-13 20:57:07 UTC
Permalink
Post by Mark Ellis
Post by Guido Diepen
Hi mark,
Post by Mark Ellis
I've disabled that line, it did indeed seem to be the problem. I've done
the same thing in enumvalue, definitely helps, don't seem to be quite
there yet.
If you would provide me with the buffer dumps of both the receiving and
sending buffers, I might be able to help out a bit. Plus a text denoting what
parameters you are trying to send and receive.
Guido Diepen
Guido, I think I've cracked it, turned out to be an unsuccessful
modification that I hadn't reverted, typical.
I'm going to double check what I have, and will hopefully commit
everything later today.
Ok, committed everything.

David, it did in fact turn out to be simply trying to read lpReserved in
both cases.

Mark
David Eriksson
2007-12-13 21:49:17 UTC
Permalink
Post by Mark Ellis
Post by Mark Ellis
Post by Guido Diepen
Hi mark,
Post by Mark Ellis
I've disabled that line, it did indeed seem to be the problem. I've done
the same thing in enumvalue, definitely helps, don't seem to be quite
there yet.
If you would provide me with the buffer dumps of both the receiving and
sending buffers, I might be able to help out a bit. Plus a text denoting what
parameters you are trying to send and receive.
Guido Diepen
Guido, I think I've cracked it, turned out to be an unsuccessful
modification that I hadn't reverted, typical.
I'm going to double check what I have, and will hopefully commit
everything later today.
Ok, committed everything.
David, it did in fact turn out to be simply trying to read lpReserved in
both cases.
Good thing you got it resolved! :-)


Cheers,

David
--

David Eriksson
2007-12-12 12:49:12 UTC
Permalink
Post by Mark Ellis
Post by David Eriksson
Response
*lpcbClass bytes optional LPWSTR lpClass
4 bytes optional data LPDWORD lpcbClass,
ignoring LPDWORD lpReserved,
4 bytes optional LPDWORD lpcSubKeys,
4 bytes optional LPDWORD lpcbMaxSubKeyLen,
4 bytes optional LPDWORD lpcbMaxClassLen,
4 bytes optional LPDWORD lpcValues,
4 bytes optional LPDWORD lpcbMaxValueNameLen,
4 bytes optional LPDWORD lpcbMaxValueLen,
4 bytes optional LPDWORD lpcbSecurityDescriptor,
8 bytes optional PFILETIME lpftLastWriteTime
Had to take out the aforementioned read of last_error. Also had to swap
lpClass and lpcbClass, ie read the size first, perfectly logical but
breaks the parameter passing order, bizarre. Do you think when M$
assigns these things for someone to spec, it explicitly states "make it
as awkward as possible".
I'll double-check this when I'm at my Windows machine again.

\David
Mark Ellis
2007-12-13 08:30:41 UTC
Permalink
Post by David Eriksson
Post by Mark Ellis
Post by David Eriksson
Response
*lpcbClass bytes optional LPWSTR lpClass
4 bytes optional data LPDWORD lpcbClass,
ignoring LPDWORD lpReserved,
4 bytes optional LPDWORD lpcSubKeys,
4 bytes optional LPDWORD lpcbMaxSubKeyLen,
4 bytes optional LPDWORD lpcbMaxClassLen,
4 bytes optional LPDWORD lpcValues,
4 bytes optional LPDWORD lpcbMaxValueNameLen,
4 bytes optional LPDWORD lpcbMaxValueLen,
4 bytes optional LPDWORD lpcbSecurityDescriptor,
8 bytes optional PFILETIME lpftLastWriteTime
Had to take out the aforementioned read of last_error. Also had to swap
lpClass and lpcbClass, ie read the size first, perfectly logical but
breaks the parameter passing order, bizarre. Do you think when M$
assigns these things for someone to spec, it explicitly states "make it
as awkward as possible".
I'll double-check this when I'm at my Windows machine again.
\David
Ignore this David, I was talking rubbish.

Mark
Guido Diepen
2007-12-12 09:06:00 UTC
Permalink
Post by Mark Ellis
Had to take out the aforementioned read of last_error. Also had to swap
lpClass and lpcbClass, ie read the size first, perfectly logical but
breaks the parameter passing order, bizarre. Do you think when M$
assigns these things for someone to spec, it explicitly states "make it
as awkward as possible".
Are you sure that you don't have the last_error value? The swapping of the
size and actual value is also what I did in my code. When I look at the
debug_buffer_dump every response I get within rapi2 always begins with 8
bytes of 0x00 for the return value and the last_error value.

Isn't the idea of obfuscating to make it difficult for reverse
engineering?? ;)
Post by Mark Ellis
Analyzing the returns can be quite fun, randomly guessing what to send
can become slightly more frustrating :)
True :)

Guido Diepen
--
Aviation is proof that given the will, we have the capacity to achieve
the impossible.
--Eddie Rickenbacker
Guido Diepen
2007-12-12 10:07:27 UTC
Permalink
Post by Mark Ellis
Time to contradict myself.
That always seems to be a problem with reverse engineering :) Had some
problems also with discovering the information :)
Post by Mark Ellis
I said that last error wasn't returned by these functions. Well it does
seem to always be zero, but I need to read it because the return value
is definitely second in the buffer. This becomes obvious when stuck in
an infinite loop when you're certain you're checking for
ERROR_NO_MORE_ITEMS :)
I'm still a uint32 short in the buffer, so what seems most likely is
that the device does not return, in the case of enumvalue, the size of
the name string, we're left to figure that out. Same applies to infokey
with regard to the class name.
Could you please give some detailed information about the actual calls
that you do, a dump of the corresponding send buffer and a dump of the
corresponding receiving buffer?

That way I might be able to help out a bit :)
Post by Mark Ellis
Anyone see any glaring errors in my reasoning ?
Nope, but making right assumptions about why microsoft choose to do
certain things might be very difficult :)

Guido Diepen
--
Aviation is proof that given the will, we have the capacity to achieve
the impossible.
--Eddie Rickenbacker
Loading...