This is possible, provided your package.xml is configured correctly. From the directions at http://boards.developerforce.com/t5/AppExchange-Directory-Packaging/Reading-complete-profiles-using-the-Metadata-API-or-sf-retrieve/td-p/213903
Using Field Trip as an example, in my package.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
<types>
<members>Field_Trip__Field_Analysis__c</members>
<name>CustomObject</name>
</types>
<types>
<members>*</members>
<name>Profile</name>
</types>
<version>25.0</version>
</Package>
In the profile XML retrieved I see:
<fieldPermissions>
<editable>true</editable>
<field>Field_Trip__Field_Analysis__c.Field_Trip__Field_Created_Date__c</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>true</editable>
<field>Field_Trip__Field_Analysis__c.Field_Trip__Label__c</field>
<readable>true</readable>
</fieldPermissions>
You should check that the current user has isAccessible() permission on the fields in the WHERE clause as well as any fields in the SELECT clause being returned to the logged in user. The reason why you need to do this check is that Apex will not throw a DML error when accessing fields that the user cannot access, so it is up to you to enforce the platform's permission model.
There is some confusion if your intuition comes from working in the developer console or via the API. The developer console runs in an execute anonymous context in which permissions are enforced. Permissions are enforced in the API as well. Permissions are not enforced in apex code running in your org, so you as the developer need to enforce them. You will not get permissions exceptions.
Also, be aware of the difference between profile perms, CRUD/FLS perms, and record sharing. Profile perms are always enforced but are only refreshed across logins. CRUD/FLS are never enforced which is why you need to make all those .isAccessible(), and isCreatable() calls before accessing, updating, deleting or inserting records. Record sharing is enforced if your class is 'with sharing'.
In terms of implementation, it's up to you as the dev to enforce programmatically whatever isn't enforced automatically by the platform, where appropriate. In some cases you may want to set a field as private/private for sharing and then ignore sharing when accessing the field. This should only be done for custom fields. In the case of sites and guest user access, you may also need to ignore CRUD/FLS, but again this should only be done for custom fields that are in your namespace. For standard fields you must always enforce CRUD/FLS (no exceptions), and you must always enforce sharing in the entry-points to your app (controllers and global classes). Hide the without sharing code in library functions invoked downstream from your entry points.
Best Answer
Regarding related lists: Permissions to see that are based on the object in the list. Some things to check:
Ensure the user otherwise has access to the object in the related list (problems could be sharing rules, access to the proper Record Type, etc. . . )
Ensure the related list is actually in the Page Layout for that combination of parent object and user Profile